Reputation: 4060
I'm asking this question to relieve myself of the confusion I've been having about the following program. I know using an array in certain contexts will make the array to decay to a single pointer to its first element. I have a function that returns this array by pointer (this function is created using new[]
). Will the array decay, causing the pointer to point only to the first element? Here is an example:
int *foo() {
int *t = new int[10];
return t;
}
int main() {
int *p = foo();
}
This is where the confusion follows. I don't know if p
points to the first element or to the entire array. So I have the following questions:
p
point to the array's first element?delete[]
on p
cause undefined behavior if the above two are true?I'm hoping these questions can be answered so I can fully understand this program. Thank you.
Upvotes: 6
Views: 5239
Reputation: 45665
Your function allocates memory and returns a pointer to it, or more technically, to the first element as you knew it correctly.
What happens with the memory afterwards is up to the caller. This means that when the array returned isn't used any longer, it should be deleted by the caller using delete[]
. If the caller doesn't respect this rule, the program leaks memory. If you write code like that, you should strongly emphasize this in the documentation of your method!
The more modern solution for stuff like that is to use smart pointers. Smart pointers are by themselves objects (not pointers to ones) which guard an underlying pointer. Depending on the type of smart pointer we are talking here, it will be deleted automatically when running out of scope in the caller (which uniquely holds the ownership to the allocated memory), or when it is no longer used by others (shared ownership).
See this question for details: smart pointers and arrays
Now if the function was written like in your question, so it returns a raw pointer rather than a smart one, you can still make use of the capabilities of smart pointers within the caller by wrapping the array afterwards.
Regarding the numbers of elements / the amount of memory to be deleted, that's completely up to the implementation of delete[]
, so you don't have to worry about the number of elements in the caller. However, you also can't query the number of elements to work with them. If you need the number of elements, you have to return them too, maybe via an "out parameter".
In modern C++, I strongly recommend using data structures different from raw arrays, like std::vector
for example, or std::map
if you need an associative container, and problems such as "who deletes this allocated memory?" are gone.
Upvotes: 6
Reputation: 227370
Does returning the array by pointer cause the decay of it (and consequentially case a memory leak)?
You are actually returning a copy of t
, which is a pointer. It already points at the first element of a dynamically allocated array. There would only be a memory leak if you failed to call delete []
on it.
Does p point to the array's first element?
Yes
Does using delete[] on p cause undefined behavior if the above two are true?
No, it is fine to do that. As long as the function is returning a pointer to a dynamically allocated array.
You have identified a serious problem with this idiom: you cannot know if you are getting a pointer to an element, a pointer to the first element of a dynamically allocated array, a pointer to a global. You cannot know by looking at the return type of the function whether you need to call delete
, delete []
, or not call delete at all. Solution: do not return a pointer! Return a type that beter expresses what is going on, and that takes care of managing its own resources (std::vector
, std::array
, std::unique_ptr
, std::shared_ptr
...).
Upvotes: 8
Reputation: 2606
Does using delete[] on p cause undefined behavior if the above two are true?
no, not delete[] p will result in a memory leak!
However, delete[] magically knows how long the array is, sizeof(p) does not, because the allocator keeps track of the allocated space. However sizeof is a fixed value generated at compiletime
Upvotes: 0