The correct answer is:
C. None of the above.
Option A:
void fill_array(Array<Type>* array_to_fill);
This is more idiomatic for pre-C++11 code where smart pointers were troublesome due to a lack of move semantics, and still continues to be the safer of the two options.
The key here is the function does not "own" the memory: it performs one task and one task only. It simply fills the array. Ownership is beyond the scope of what it does and it is mostly safe.
Option B:
Array<Type>* filled_array();
This creates an object inside the function. There are generally two ways to do this:
- Return a pointer to a local (stack) object. This pointer will not be valid for long and will break something (UB).
- Return a pointer to a dynamically allocated (heap) object. Who owns the object? Where and when is its memory freed? In some architectures this can pose additional problems. For example, the Windows platform does not allow memory allocated in one module to be freed in another (i.e. cannot allocate in DLL 1 and free in DLL 2).
Option C:
std::unique_ptr<Array<Type>> filled_array();
This is the absolute correct, efficient, guaranteed-to-work way.
The memory is owned by the smart pointer, and will be freed when the pointer goes out of scope (RAII) and has no other pointer to hand it off to.
Inside the function, there will be a smart pointer assigned a new array instance. The smart pointer owns that array pointer.
The function then invokes behavior through that pointer, adding data.
When the function is done, it returns the smart pointer. Since the smart pointer goes out of scope, it destructs. However, it moves the pointer it contains to a new instance in the calling location. (Note: the compiler may be able to construct the smart pointer in-place in the calling location. Regardless, smart pointers are extremely lightweight and the difference is minimal).
Now you have a smart pointer in the calling location that owns the array it points to, and that array will be freed according to the standard RAII rules. There are no dangling pointers, no memory leaks, just code that does exactly what it appears to.