简体   繁体   中英

Explain how this C++ function returns an array

I found this code online http://www.cplusplus.com/forum/beginner/6644/#msg30551 which is supposed to return an array from a c++ function. I would like an explanation illustrating how this function operates with respect to memory allocation, stacks, heaps, pointers etc.

int *f(size_t s){
    int *ret=new int[s];
    for (size_t a=0;a<s;a++)
        ret[a]=a;
    return ret;
}

I.

int *ret=new int[s];

1. allocate memory for ret on the stack - this is an int pointer
2. allocate continuous memory with size s * sizeof(int) on the heap
3. make ret to point to the first element of the allocated memory (from 2.)


II.

for (size_t a=0;a<s;a++)
    ret[a]=a;
  1. allocates memory on the stack for a
  2. loop through the allocated memory in I., assigning values to each element
  3. After the end of the for -statement, a is no longer accessible (it's available only in the for )

III.

return ret;

return a copy of the ret pointer , which points to the first element of the created in I. array, initialized in II.

After the return , ret is "destroyed".


The caller of this function must not forget to deallocate (free) this memory, invoking delete[] .

For example:

int * my_array = f( 6 );
// do sth with my_array
delete[] my_array;

Actually, the function doesn't return an array of int s (ie int[N] ). What it returns is a pointer to an int ( int * ). It turns out that this pointer points to the first element of an array of s elements of type int .

Notice that the memory is allocated with new :

int *ret = new int[s];

Therefore, the array of int s pointed by ret has dynamic storage duration. Among other things, this implies that

1) the compiler will not automatically call each array element's destructor. (In this case this isn't a problem because the elements are of type int but could be if, instead, the elemets where of a class type with a non-trivial destructor.)

2) the compiler will not automatically free the allocated memory.

To contrast, consider the following code:

void g() {
    int p[10]; // allocates 10 integer in the stack
    // use p ...
}

When g terminates the compiler will perform the aforementioned operations. For this to work, the size of the array (10 in this example) must be set at compile time. If you don't know the size at compile time than you need new as in the original code.

For dynamic allocated arrays, it's the programmer's responsibility to ensure that the two aforementioned operations are performed when the array is no longer needed. To accomplish this, you must call delete[] :

delete[] p; // where p is a `int*` with the same value as `ret`

In practice, this is more difficult than it seems due to the possibility of exceptions being thrown. For instance, consider this code

void foo() {
    int* p = f(10); // where f is in the question
    // ... use the array pointed by p
    a_function_that_might_throw();
    delete[] p;
}

If a_function_that_might_throw does throw an exception then the execution never reachs the point where p is deleted. In this case, the memory allocated by new (inside f ) will not be freed (it leaks) until the program terminates.

To avoid this problem, instead of a raw pointer (eg int* ) it's better to use a smart pointer (eg std::unique_ptr or std::shared_ptr ).

Finally, by default, the memory allocated by new is heap memory. However, you can change this behavior.

Arrays and pointers have a lot of similarities. You can have a pointer to first element of an array and pass it (or return it) to somewhere you want.

int *f(size_t s) // It will return a pointer (maybe first element of an array)
{
    int *ret=new int[s]; // Allocates memory in heap,
                         // An array with s integral elements,
                         // And stores the address of the array in ret

    for (size_t a=0;a<s;a++)
        ret[a]=a;

    return ret; // Returns the pointer which points first element of the array
}
// ...
int *z = f(10); // z points to the first element of returned array

// ... then you're responsible to free the allocated memory ... 
// delete [] z;
int *ret=new int[s];

This line defines a int* called ret with automatic storage duration. It initialises ret with the pointer returned by the new-expression new int[s] . This new-expression creates an array of s int s with dynamic storage duration, returning a pointer to the first element in that array.

So we now have two objects: an int* with automatic storage duration and an int[] with dynamic storage duration.

for (size_t a=0;a<s;a++)

This is a for statement. The for-init-statement defines a size_t object called a and initialises it to 0. The condition checks whether a is less than s . The final expression increments a . This means that a loops in the range [0, s) .

ret[a]=a;

This assigns the value of a to the a th element in ret . That is ret[0] will have the value 0 , ret[1] will have the value 1 , and so on.

The a object is now destroyed because it had automatic storage duration and we have reached the end of its scope (the for statement).

return ret;

This returns the value of ret , which as you remember was an int* . The return value of the function is therefore an int* pointing at the first element of the dynamically allocated array.

The ret object is now destroyed because it had automatic storage duration and we have reached the end of its scope (the f function). Note that this is just the pointer inside the function. The dynamically allocated array still exists and the returned pointer still points to it.

You must, at some later point, remember to delete[] the returned pointer.

int *ret =  new int[s];

This dynamically (~ on the heap) allocates an array of s integers and stores a pointer to it (actually, to its first element) in ret .

I believe the rest of the function is straightforward.

So the function is handing back a pointer to a dynamically allocated array. It's not really safe; if the caller does not store the return value and later call delete[] on it, it will leak.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM