Do you need to de-allocate an array of primitives? - c++

If I have an array of a primitive type for example: int A[] = new int[10];
Would it create a memory leak if not freed?
This is a question that popped into my head recently. I'm sure I learned it in school, but it's been such a long time since I've used C/C++ I can't remember exactly. As it was, creating any object with "new" puts that object on the heap which must be freed/destroyed at some point. I remember doing this with arrays of objects and it would make sense to do so, but I don't ever remember needing to free an array of int or String. So is this case with primitive arrays as well?
thanks
Will

If you allocate something with new, and it isn't handed off to a smart-pointer or something for management, you have to delete it. It doesn't matter whether it's an object or a primitive type.
Be careful with the word "free" here. You shouldn't use the function free on anything that was allocated with new. Also make sure you understand the difference between delete and delete[].
Even better, use std::vector instead of dynamic arrays and you don't have to worry about deleting anything.

Related

When do you need to delete C-style arrays?

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.
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....
You always and only use delete when you have used new and delete[] when you have used new[]. Never mix them. And never mix with (2).
You always and only use 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.
TL;DR
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?
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.

C++ Check if array created with 'new'

In C++ the delete[] is supposed to be used with arrays created by new. You can pass arrays into functions like this: void method_with_array(int* array). How can you tell if an array created this way was created with new, so you can delete it properly.
You can't, so better not pass around pointers to things created with new or new[]. Use for example std::vector or if you really really really need a dynamically allocated array, std::unique_ptr<T[]>.
Usually a good rule is that whoever takes care of the allocation of an object should take care of releasing the object.
That said, if you are allocating and deleting the memory for an object in the same object/container/manager, you know what you are dealing with. In case the same pointer is used for one or multiple elements, you have different options:
keep a variable that tells you which kind of int* member you have allocated
allocate all the times an array, eventually of size 1
use an std::vector even for storing a single element, as above.

What do I have to garbage collect in a C++ destructor

I'm writing a C++ destructor (I hope that's the right term; I'm new to C++) and I'm not positive on what exactly I need to garbage collect. Let's say I have 2 pointers as instance variables do I need to garbage collect them? What about if I have an object as an instance variable? Or a pointer to an object?
I'm just a little fuzzy on what exactly needs to be deleted and what is automatically cleaned up.
Thanks
General rule of thumb is... if you called new, call delete. If you called new[], call delete[]. If you're accessing these pointers outside of the class and effectively sharing them, you'll want to be careful about the "owning" object deleteing the shared objects while they're still in use. Garbage collection isn't quite the right term. You want to destroy the object and free its memory. This is what delete/delete[] does. new/new[] allocate memory and construct an object.
In C++, there is no garbage collector. You must "manually" handle it. That's not to say that it's all tedium. You'll probably get into using smart pointers to handle some of this logic for you. See this question for more information.
You must delete every pointer you allocate with new. It's that simple, and it's that complicated; you must not lose track of any pointer allocated by new until you have deleted it.
Also, you need to make sure that if you use new[] to allocate a pointer, you call delete[] to deallocate it.
It's not about what pointers you happen to have in a class instance. You need to know who owns them (the owner is the one responsible for deleting them). If your object owns those pointers, then it should delete them. If it doesn't own them, then it shouldn't.
This is also why experienced C++ programmers avoid naked pointers where possible. Smart pointers allow you to express ownership types semantically in the language. That way, you don't have to keep track of who owns what; you know who owns it by the type of smart pointer being used.
You must call delete on every space you created using new, delete[] on every area created using new[], and free on everything you got using malloc.
You should also close any sockets you opened, and clear up any other OS resources your class owns.
Note: this is not called garbage collection. Garbage collection is when this process happens automatically, as part of a library or language runtime, not when you do it explicitly.
You should start by learning about "Resource Acquisition is Initialization" (RAII) and smart pointers (shared_ptr and unique_ptr). This is the idiom you have to know in C++ if you come from other languages.
Usual practice says that whatever you allocated in your constructor must be deallocated in your destructor (see other answers to know how). Event better, try to use values as much as possible and new as less as possible.
C++ loves the stack, and stack allocation and deallocation are automatic and cheap (no new, no delete). Use references and const-references instead of pointers.
If you really need dynamic memory, try to use one of the smart pointers.
Any memory you allocate using new operator needs to be freed.
You allocate memory by doing:
int * p1 = new int[5];
p2 = new int;
and you delete it by doing:
delete[] p1
delete p2;
If you are playing with Classes, you need to do the same thing in constructors (allocate) and destructors (deallocate).
In an ideal world, nothing. There are smart pointers and containers for every pattern. Sometimes, you will have to write your own, or augment existing implementations, but much of what you need exists already.
For an array, start with std::array and std::vector. For objects, read up on smart pointers and shared pointers. As a generalization: if you need to call delete, delete[] or free, you have usually headed down the wrong path.
You need to garbage collect all pointers that you don't no longer need. Otherwise you would have the dangling pointer problem.

A destructor - should I use delete or delete[]?

I am writing a template class that takes as an input a pointer and stores it. The pointer is meant to point to an object allocated by another class, and handed to the this containing class.
Now I want to create a destructor for this container. How should I free the memory pointed to by this pointer? I have no way of knowing a priori whether it is an array or a single element.
I'm sort of new to C++, so bear with me. I've always used C, and Java is my OO language of choice, but between wanting to learn C++ and the speed requirements of my project, I've gone with C++.
Would it be a better idea to change the container from a template to a container for an abstract class that can implement its own destructor?
If you don't know whether it was allocated with new or new[], then it is not safe to delete it.
Your code may appear to work. For example, on one platform I work on, the difference only matters when you have an array of objects that have destructors. So, you do this:
// by luck, this works on my preferred platform
// don't do this - just an example of why your code seems to work
int *ints = new int[20];
delete ints;
but then you do this:
// crashes on my platform
std::string *strings = new std::string[10];
delete strings;
You must document how this class expects to be used, and always allocate as expected. You can also pass a flag to the object specifying how it should destroy. Also look at boost's smart pointers, which can handle this distinction for you.
Short answer:
If you use [] with new you want to use [] with delete.
//allocate some memory
myObject* m = new myObject[100];
//later on...destructor...
delete m; //wrong
delete[] m; //correct
That was the bare bones, the other thing you could look at is boost. Also quite difficult to answer considering you are not sure if its an array or single object. You could check this though via a flag telling your app whether to use delete or delete[].
As a general development rule, you should stick to a design where the class which calls new should also call delete
You shouldn't delete it at all. If your class takes an already initialized pointer, it is not safe to delete it. It might not even point to an object on the heap; calling either delete or delete[] could be disastrous.
The allocation and deallocation of memory should happen in the same scope. Which ever code owns and initializes the instance of your class is also presumably responsible for initializing and passing in the pointer, and that is where your delete should be.
Use delete if you allocated with new.
Use delete[] if you allocated with new[].
After these statements, if you still have a problem (maybe you want to delete an object that was created by someone else), then you are breaking the third rule:
Always delete what you created. Corollary, never delete what you did not create.
(Moving my comment into an answer, by request.)
JonH's answer is right (about using array destruction only when you used array construction), so perhaps you should offer templates: one for arrays, one not.
The other answer is to avoid arrays and instead expect a single instance that may or may not be a proper collection that cleans up after itself, such as vector<>.
edit
Stealing blatantly from Roger Pate, I'll add that you could require the use of a smart pointer, which amounts to a single-item collection.
If you have a class that takes a pointer it's going assume ownership of, then the contract for the use of the class needs to include one of a couple things. Either:
the interface needs to indicate how the object the pointer is pointing to was allocated so the new owner can know how to safely deallocate the object. This option has the advantage of keeping things simple (on one level anyway), but it's not flexible - the class can't handle taking ownership of static objects as well as dynamically allocated objects.
or
the interface needs to include a mechanism where a deallocation policy can be specified by whatever is giving the pointer to the class. This can be as simple as providing a mechanism to pass in a functor (or even a plain old function pointer) that will be called to deallocate the object (preferably in the same function/constructor that passes in the pointer itself). This makes the class arguably more complicated to use (but having a default policy of calling delete on the pointer, for example, might make it as easy to use as option 1 for the majority of uses). Now if someone wants to give the class a pointer to a statically allocated object, they can pass in a no-op functor so nothing happens when the class wants to deallocates it, or a functor to a delete[] operation if the object was allocated by new[], etc.
Since pointer in C++ does not tell us how it was allocated, yes, there's no way to decide what deallocation method to use. The solution is to give the choice to the user that hopefully knows how the memory was allocated. Take a look at Boost smart ptr library, especially at shared_ptr constructor with second parameter, for a great example.
A smart pointer like boost shared_pointer already has this covered, could you use it? linky
Put simply, given only a pointer to dynamically allocated memory there is no way of determining how to de-allocate it safely. The pointer could have been allocated in any of the the following ways:
using new
using new []
using malloc
using a user defined function
etc.
In all cases before you can deallocate the memory you have to know how it was allocated.

Why is there a special new and delete for arrays?

What is wrong with using delete instead of delete[]?
Is there something special happening under the covers for allocating and freeing arrays?
Why would it be different from malloc and free?
Objects created with new[] must use delete[]. Using delete is undefined on arrays.
With malloc and free you have a more simple situation. There is only 1 function that frees the data you allocate, there is no concept of a destructor being called either. The confusion just comes in because delete[] and delete look similar. Actually they are 2 completely different functions.
Using delete won't call the correct function to delete the memory. It should call delete[](void*) but instead it calls delete(void*). For this reason you can't rely on using delete for memory allocated with new[]
See this C++ FAQ
[16.13] Can I drop the [] when
deleteing array of some built-in type
(char, int, etc)?
No!
Sometimes programmers think that the
[] in the delete[] p only exists so
the compiler will call the appropriate
destructors for all elements in the
array. Because of this reasoning, they
assume that an array of some built-in
type such as char or int can be
deleted without the []. E.g., they
assume the following is valid code:
void userCode(int n) {
char* p = new char[n];
...
delete p; // ← ERROR! Should be delete[] p !
}
But the above code is wrong, and it
can cause a disaster at runtime. In
particular, the code that's called for
delete p is operator delete(void*),
but the code that's called for
delete[] p is operator
delete[](void*). The default behavior
for the latter is to call the former,
but users are allowed to replace the
latter with a different behavior (in
which case they would normally also
replace the corresponding new code in
operator new[](size_t)). If they
replaced the delete[] code so it
wasn't compatible with the delete
code, and you called the wrong one
(i.e., if you said delete p rather
than delete[] p), you could end up
with a disaster at runtime.
Why does delete[] exist in the first place?
Whether you do x or y:
char * x = new char[100];
char * y = new char;
Both are stored in char * typed variables.
I think the reason for the decision of delete, and delete[] goes along with a long list of decisions that are in favor of efficiency in C++. It is so that there is no enforced price to do a lookup of how much needs to be deleted for a normal delete operation.
Having 2 new and new[] seems only logical to have delete and delete[] anyway for symmetry.
The difference is that delete will only delete the entire memory range, but will only call the destructor for 1 object. delete[] will both delete the memory and call the destructor for every single object. If you do not use delete[] for arrays, it's only a matter of time before you introduce a resource leak into your application.
EDIT Update
According to the standard, passing an object allocated with new[] to delete is undefined. The likely behavior is that it will act as I described.
Stroustrup talks about the reasons for separate new/new[] and delete/delete[]` operators in "The Design and Evolution of C++" in sections 10.3 through 10.5.1:
10.3 Array Allocation - discusses that they wanted a way to allow arrays of objects to be allocated using a separate scheme from allocation single objects (ie., allocating arrays from a separate store). Adding the array versions of new and delete was a solution for this;
10.5.1 Deallocating Arrays - discusses how a problem with deallocating arrays using just a single delete operator is that there needs to be more information than just the pointer in order to determine if the pointer points to the first element of an array or if it just points to a single object. Instead of "complicating the common case of allocating and deallocating individual objects", the delete[] operator is used to handle arrays. This fits in with the general C++ design philiosophy of "don't pay for what you don't use".
Whether this decision was a mistake or not is debatable - either way has good arguments, but we have what we have.
The reason for this requirement is historical and because new type and new type [size] return different things that need to be cleaned up differently.
Consider this code
Foo* oneEntry = new Foo;
Foo* tenEntries = new Foo[10];
These both return a Foo* pointer, the difference is the second call will result in the Foo constructor being called 10x, and there being roughly 10x as much memory.
So now you want to free your objects.
For a single object you would call delete - e.g. delete oneEntry. This calls the objects destructor and and deallocates the memory.
But here's the problem - oneEntry and tenEntries are both just Foo pointers. The compiler has no idea whether they point to one, ten, or a thousand elements.
When you use the special syntax of delete []. This tells the compiler "this is an array of objects, figure out the count and then destruct them all".
What really happens is that for new type [size] the compiler secretly stores 'size' somewhere else. When you call delete[] it knows that this secret value exists so it can find out how many objects are in that block of memory and destruct them.
The question you could then ask is "why doesn't the compiler always store the size?"
That's a great question and it dates back to the early days of C++. There was a desire that for built-in types (char, int, float, etc) the following would be valid for C++;
int* ptr = new int;
free(ptr);
int* ptr = (int*)malloc(sizeof(int) * someSize);
delete ptr;
The reasoning behind this was an expectation that people would provide libraries that returned dynamically allocated memory, and users of these libraries would have no way of knowing whether to use free/delete.
This desire for compatibility meant that the size of an array could not be stored as part of the array itself and had to be kept elsewhere. Because of this overhead (and remember, this was back in the early 80's) it was decided to do this book keeping only for arrays and not single-elements. Thus arrays need a special delete syntax that looks up this value.
The reason malloc/free do not have this problem is that they simply deal with blocks of memory and do not have to worry about calling constructors/destructors.
As to the "why" in the title: one of the design goals of C++ was that there wouldn't be any hidden costs. C++ was also developed at a time when every byte of memory still mattered a whole lot more than it does today. Language designers also like orthogonality: if you allocate the memory with new[] (instead of new), you should free it with delete[].
I don't think there's any technical reason that new[] couldn't stick an "I'm an array" flag in the header of the memory block for delete (no more delete[]) to look at later.
new and delete are different from malloc and free in that malloc and free only allocate and free memory; they don't call ctors or dtors.
When you use new[] to allocate an array, you are actually telling C++ the size of the array. When you use malloc, you are instead telling it how much memory is allocated. In the former case, freeing based on the size of the array would not make sense. In this case, it does. But since there is no difference between a pointer for an array vs. for a single object, a separate function is needed.