Reputation: 2789
I was reading an excellent answer to another question which gave these specific examples:
char[] array = {'a', 'b', 'c', '\0'};
Thing* t = new Thing[size];
t[someindex].dosomething();
I commented that, as good practice, you should add delete[]
to the second example, as this is the bit people forget leading to memory leaks.
But I can't remember if you need to delete[]
in the first instance. I don't think you do, because there's no new
so it's on the stack, but I'm not 100% sure that's right.
Upvotes: 7
Views: 3971
Reputation: 31409
delete
when you have used new
and delete[]
when you have used new[]
. Never mix them. And never mix with (2).free
when you have made a classic C allocation like malloc
or calloc
. Never mix with (1). But don't free memory allocated with alloca
;)Note that in some cases, the allocation or deallocation can be hidden inside a function or something. For instance, there is a non standard C-function that copies a string like this: char *str = strdup("Hello");
. In this case, you should use free(str)
even though you did not manually invoke malloc
.
So if you do a declaration on the form T t[10]
or T[] t={a,b,c}
you do NOT deallocate this.
int main()
{
int x;
std::cin << x;
T *a = new T;
delete a;
T *b = new T[x];
delete[] b;
T *c = (T*)malloc(x*sizeof(*c)); // Casting is needed in C++ but not in C
free(c);
// No free or delete for these
T d;
T e[10];
// Assuming a, b and c are instances of T or that you have overloaded the
// operator so that you can write T t=a;
// In either case, you should not free nor delete this
T f[] = {a, b, c};
}
In C, you can use VLA:s like int arr[x]
where x
is not known at compile time. That's not possible in C++. You don't use free on these arrays either.
I don't think you do, because there's no new so it's on the stack, but I'm not 100% sure that's right.
This is not correct. The standard does not dictate if the objects should be on the stack or the heap. It's up to the compiler, so what happens in reality is a question of how compilers usually solves the task.
Furthermore, the "fact" that statically allocated memory ends up on the stack and dynamically allocated memory ends up on the heap is only true most of the time. Granted, this is usually what happens, but there are some rare cases when it's not. And these occurrences are not so rare or obscure that they can be ignored. Global variables typically does not end up on the stack.
So if memory should be freed/deleted is not a question of if it lives in the stack or the heap. It's about how it has been allocated.
And in modern C++ you very rarely use new
, new[]
, delete
or delete[]
at all. Instead, you use smart pointers and containers. Look at this link:
What is a smart pointer and when should I use one? and also https://en.cppreference.com/w/cpp/container/vector If you are dealing with old legacy C++, it might be a good idea to refactor it to modern memory management. If you change a new
-delete
pair to a smart pointer, then you have saved a line. If you change a new
without a corresponding delete
, then you have solved a bug.
When do you need to delete C-style arrays?
For the case T a[n]
(with or without initialization) you should never do it. For the case T *a = new T[n]
you should always do it. Whenever you have used new
you should delete
it afterwards, and never otherwise. (There may be some rare exceptions to this. See the rest of the post.)
Also, AFIK, there is no established definition of "C-style arrays". Personally, I would not consider T *a = new T[n]
an array at all. I would not consider T *a = malloc(n*sizeof(*a))
an array either. The reason is simple. Pointers and arrays are NOT the same thing, and this goes for both C and C++. This question is about C, but is applicable for C++ too: Is an array name a pointer?
Upvotes: 10
Reputation: 24077
I don't think you do, because there's no new so it's on the stack, but I'm not 100% sure that's right.
This reasoning is correct when the array
is defined inside a function, and is therefore on the stack. You must never use delete
on any objects that have been created on the stack without the use of new
. Using delete
on stack allocated objects will lead to undefined behavior.
If the definition char[] array = {'a', 'b', 'c', '\0'};
appeared at file scope, however, it will have static storage duration and will not be on the stack, but it still won't have been dynamically allocated and still must not be delete[]
d.
So, either way, don't delete[]
the array....
Upvotes: 13
Reputation: 2406
I commented that, as good practice, you should add delete[] to the second example, as this is the bit people forget leading to memory leaks.
You also should add delete[]
in order to get destructors called. In addition to releasing some internally allocated memory, destructors may have other side effects.
Semantically, new
and delete
(and new[]
and delete[]
) come in pairs. new
starts the object lifetime, and delete
ends the object lifetime started by new
. However, usually it is advisable to make deletion hidden inside a smart pointer.
The idea is to bind object lifetimes to the notion of "object ownership". Static objects are owned by the whole program. Automatic objects are owned by the code block they are defined in. Dynamic objects have no clearly defined ownership in C++ language itself, although the language gives the tools to implement the notion of object ownership by the writers of the code.
Smart pointers are one of these tools. std::unique_ptr
is used when at every moment of time the object has only one owner, but you may want to pass ownership between blocks of code. std::shared_ptr
is used when there can be multiple owners, and the object lifetime should end when the last owner stops to be interested in the object.
Upvotes: 5