The array arr
is declared local to the function. As a result its lifetime ends when the function exits. We call this automatic lifetime. Returning a pointer to this memory invokes undefined behavior. The code might work the way you expect, or it might not.
To work around this, you need a lifetime that is not automatic, and which can be controlled. There are a few paths to this.
Manual memory management
You might use dynamic memory management with new
and delete
(or in this case delete []
). This is generally discouraged as it creates many opportunities for mistakes.
int *example() {
int *a = new int[3] { 1, 2, 3 };
return a;
}
You would need to remember to delete this array.
int main() {
int *a = example();
cout << a[0] << endl;
cout << a[1] << endl;
cout << a[2] << endl;
delete[] a;
return 0;
}
Smart pointers
You could use a smart pointer, which makes explicitly deallocating unnecessary, as the memory it points to is deallocated when the smart pointer goes out of scope.
unique_ptr<int[]> example() {
auto a = unique_ptr<int[]>(new int[3] { 1, 2, 3 });
return a;
}
int main() {
auto a = example();
cout << a[0] << endl;
cout << a[1] << endl;
cout << a[2] << endl;
return 0;
}
STL containers
The most idiomatic approach is to use an STL container class.
The std::array
container maps directly to the fixed size arrays seen so far. The std::vector
container is more appropriate if the size is unknown at compile time, which it often will be, making this a very common container to see in idiomatic C++ code.
As with the smart pointer, the memory does not have automatic storage duration, so it can live beyond the scope in which it's declared, and the data is deallocated when the container goes out of scope.
array<int, 3> example() {
array<int, 3> a = { 1, 2, 3 };
return a;
}
int main() {
auto a = example();
cout << a[0] << endl;
cout << a[1] << endl;
cout << a[2] << endl;
return 0;
}