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.
Related
I came across an article on new / operator new:
The many faces of operator new in C++
I couldn't understand the following example:
int main(int argc, const char* argv[])
{
char mem[sizeof(int)];
int* iptr2 = new (mem) int;
delete iptr2; // Whoops, segmentation fault!
return 0;
}
Here, the memory for int wasn't allocated using new, hence the segfault for delete.
What exactly does delete not like here? Is there some additional structure hidden when an object is initialized with new, that delete looks for?
EDIT:
I'll take out of comments several responses which helped me to understand the situation better:
As #463035818_is_not_a_number and #HolyBlackCat pointed out, mem was allocated on the stack, while delete tries to free memory on the heap. It's a pretty clear cut error and should lead to a segfault on most architectures.
If mem was allocated on the heap without an appropriate new:
The only way to do it I know would be, say, to allocate an int* on a heap, then reinterpret_cast it to an array of chars and give delete a char pointer. On a couple of architectures I tried this on, it actually works, but leads to a memory leak. In general, the C++ standard makes no guarantees in this case, because doing so would make binding assumption on the underlying architecture.
delete deletes objects from the heap. Your object is on the stack, not on the heap.
new (new T, not the placement-new you used) does two things: allocates heap memory (similar to malloc()), then performs initialization (for classes, calls a constructor).
Placement-new (what you used) performs initialization in existing memory, it doesn't allocate its own.
And delete does two things: calls the destructor (for class types), then frees the heap memory (similar to free()).
Since your object is not on the heap, delete can't delete its memory.
There's no "placement-delete" that only calls the destructor. Instead, we have manual destructor calls:
If you had a class type, you'd do iptr2->MyClass::~MyClass(); to call the destructor. And freeing the memory is then unnecessary since stack memory is automatically deallocated when leaving the current scope.
Also note that you forgot alignas(int) on your char array.
What exactly delete doesn't like here?
The fact that it was called for a pointer that did not come from a real new.
Is there some additional structure hidden when an object is initialized
with new, that it looks for?
That is a near certainty for your C++ implementation, but it's completely immaterial. This is undefined behavior, full stop. delete is defined only for pointers to objects that were created with a non-placement new operator. Otherwise this is undefined behavior. This is an important distinction. The "your C++ implementation" part is relevant. It's certainly possible that a different C++ compiler or operating system will produce code that doesn't crash, and does nothing at all. Or it may draw a funny face on your monitor screen. Or play a tune that you hate, on your speakers. This is what "undefined behavior" means. And in this case, "undefined behavior" means a crash, in your case.
You can only delete what has been allocated via new.
As explained in the article, placement new, skips the allocation:
Calling placement new directly skips the first step of object allocation. We don't ask for memory from the OS. Rather, we tell it where there's memory to construct the object in [3]. The following code sample should clarify this:
You cannot delete mem because it has not been allocated via new. mem has automatic storage duration and gets freed when main returns.
Placement new in your code creates an int in already allocated memory. If int had a destructor you would need to call the destructor (but not deallcoate the memory). Placing the int in the memory of mem does not change the fact that mem is allocated on the stack.
Actually the placement new in the code is not that relevant for the issue in the code. Also this code
int main(int argc, const char* argv[])
{
char mem[sizeof(int)];
delete iptr2; // Whoops, Undefined
return 0;
}
Has undefined behavior just as your code has.
There are several flavours of new and delete.
The (non-placement) new operator allocates memory by calling the operator new() function. The delete operator frees memory by calling the operator delete() function. They are a pair.
(Confused yet? Read this, or maybe this).
The new[] operator allocates memory by calling the operator new[]() function. The delete[] operator frees memory by calling the operator delete[]() function. They are a different pair.
The placement new operator does not allocate memory and does not call any kind of operator new()-like function. There is no corresponding delete operator or operator delete()-like function.
You cannot mix new of one flavour with delete of a different flavour, it makes no sense and the behaviour is undefined.
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.
This question already has answers here:
Is delete[] equal to delete?
(6 answers)
Closed 9 years ago.
In C, free() is used to release the memory, say free(ptr). As I understand, extra memory is allocated before ptr in the library code to store the block size information. After free() is called, the whole block is tracked and then released.
In C++, there are two forms of new and delete. One is for array. If new[] is used, delete[] should be used. For example,
int ptr = new [10];
delete [] ptr;
Question 1: can I use delete ptr here? If that is OK, what if delete ptr + 2?
Question 2: If delete[] has to be used to match new[], why do we need two forms of delete? Just one form, say delete, would be enough.
Thanks for all the suggestions!
Thank Mgetz. Question 2 should be: why c++ standard proposed both delete [] and delete if there is only one correct form at any situation?
Q1: You can use delete, but it is wrong.
This will usually "work" insofar as it will correctly free the allocated memory, but it will not call destructors properly. For trivial types, you will often not see any difference, but that doesn't mean it isn't wrong anyway. In any case it is undefined behavior which you should avoid if you can (invoking UB forfeits any guarantees that your code will work, it might of course still work, but you can never be 100% sure).
Deleting ptr+2 is also undefined behavior and will almost certainly not "work", not even a little. Usually, this will simply result in a program crash.
Q2: You need the two because they mean different things. One means "delete this pointer-to-single-object" whereas the other means "delete this pointer-to-array-of-objects".
Obviously, the compiler needs to generate different code for those different things.
You need the two forms because, unlike malloc and free, new and delete do more than just allocate and deallocate memory; they also construct and destruct the object(s) respectively.
new and delete deal with scalar objects, while new[] and delete[] deal with arrays of objects.
When you call new T[n], it'll allocate enough memory for n copies of T, and then construct n instances within the allocated memory. Similarly, calling delete[] will cause destruction of those n instances followed by deallocation.
Obviously, since you do not pass n to delete[] that information is being stashed away somewhere by the implementation, but the standard doesn't require an implementation to destroy all n objects if you call delete instead. The implementation could just destroy the first object, it might behave correctly and destroy all n objects or it might cause demons to fly out of your nose.
Simply put, it's undefined behavior, there's no telling what'll happen, it's best imperative you avoid it.
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
( POD )freeing memory : is delete[] equal to delete ?
Does delete deallocate the elements beyond the first in an array?
char *s = new char[n];
delete s;
Does it matter in the above case seeing as all the elements of s are allocated contiguously, and it shouldn't be possible to delete only a portion of the array?
For more complex types, would delete call the destructor of objects beyond the first one?
Object *p = new Object[n];
delete p;
How can delete[] deduce the number of Objects beyond the first, wouldn't this mean it must know the size of the allocated memory region? What if the memory region was allocated with some overhang for performance reasons? For example one could assume that not all allocators would provide a granularity of a single byte. Then any particular allocation could exceed the required size for each element by a whole element or more.
For primitive types, such as char, int, is there any difference between:
int *p = new int[n];
delete p;
delete[] p;
free p;
Except for the routes taken by the respective calls through the delete->free deallocation machinery?
It's undefined behaviour (most likely will corrupt heap or crash the program immediately) and you should never do it. Only free memory with a primitive corresponding to the one used to allocate that memory.
Violating this rule may lead to proper functioning by coincidence, but the program can break once anything is changed - the compiler, the runtime, the compiler settings. You should never rely on such proper functioning and expect it.
delete[] uses compiler-specific service data for determining the number of elements. Usually a bigger block is allocated when new[] is called, the number is stored at the beginning and the caller is given the address behind the stored number. Anyway delete[] relies on the block being allocated by new[], not anything else. If you pair anything except new[] with delete[] or vice versa you run into undefined behaviour.
Read the FAQ: 16.3 Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?
Does it matter in the above case seeing as all the elements of s are allocated contiguously, and it shouldn't be possible to delete only a portion of the array?
Yes it does.
How can delete[] deduce the number of Objects beyond the first, wouldn't this mean it must know the size of the allocated memory region?
The compiler needs to know. See FAQ 16.11
Because the compiler stores that information.
What I mean is the compiler needs different deletes to generate appropriate book-keeping code. I hope this is clear now.
Yes, this is dangerous!
Dont do it!
It will lead to programm crashes or even worse behavior!
For objects allocated with new you MUST use delete;
For objects allocated with new [] you MUST use delete [];
For objects allocated with malloc() or calloc() you MUST use free();
Be aware also that for all these cases its illegal to delete/free a already deleted/freed pointer a second time. free may also NOT be called with null. calling delete/delete[] with NULL is legal.
Yes, there's a real practical danger. Even implementation details aside, remember that operator new/operator delete and operator new[]/operator delete[] functions can be replaced completely independently. For this reason, it is wise to think of new/delete, new[]/delete[], malloc/free etc. as different, completely independent methods of memory allocaton, which have absolutely nothing in common.
Raymond Chen (Microsoft developer) has an in-depth article covering scaler vs. vector deletes, and gives some background to the differences. See:
http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx
Does delete deallocate the elements
beyond the first in an array?
No. delete will deallocate only the first element regardless on which compiler you do this. It may work in some cases but that's co-incidental.
Does it matter in the above case seeing as all the elements of s are allocated
contiguously, and it shouldn't be possible to delete only a portion of the array?
Depends on how the memory is marke as free. Again implementation dependant.
For more complex types, would delete call the destructor of objects beyond the first one?
No. Try this:
#include <cstdio>
class DelTest {
static int next;
int i;
public:
DelTest() : i(next++) { printf("Allocated %d\n", i); }
~DelTest(){ printf("Deleted %d\n", i); }
};
int DelTest::next = 0;
int main(){
DelTest *p = new DelTest[5];
delete p;
return 0;
}
How can delete[] deduce the number of
Objects beyond the first, wouldn't
this mean it must know the size of the
allocated memory region?
Yes, the size is stored some place. Where it is stored depends on implementation. Example, the allocator could store the size in a header preceding the allocated address.
What if the memory region was
allocated with some overhang for
performance reasons? For example one
could assume that not all allocators
would provide a granularity of a
single byte. Then any particular
allocation could exceed the required
size for each element by a whole
element or more.
It is for this reason that the returned address is made to align to word boundaries. The "overhang" can be seen using the sizeof operator and applies to objects on the stack as well.
For primitive types, such as char, int, is there any difference between ...?
Yes. malloc and new could be using separate blocks of memory. Even if this were not the case, it's a good practice not to assume they are the same.
It's undefined behavior. Hence, the anser is: yes, there could be danger. And it's impossible to predict exactly what will trigger problems. Even if it works one time, will it work again? Does it depend on the type? Element count?
For primitive types, such as char, int, is there any difference between:
I'd say you'll get undefined behaviour. So you shouldn't count on stable behaviour. You should always use new/delete, new[]/delete[] and malloc/free pairs.
Although it might seem in some logic way that you can mix new[] and free or delete instead of delete[], this is under the assumption about the compiler being a fairly simplistic, i.e., that it will always use malloc() to implement the memory allocation for new[].
The problem is that if your compiler has a smart enough optimizer it might see that there is no "delete[]" corresponding to the new[] for the object you created. It might therefore assume that it can fetch the memory for it from anywhere, including the stack in order to save the cost of calling the real malloc() for the new[]. Then when you try to call free() or the wrong kind of delete on it, it is likely to malfunction hard.
Step 1 read this: what-is-the-difference-between-new-delete-and-malloc-free
You are only looking at what you see on the developer side.
What you are not considering is how the std lib does memory management.
The first difference is that new and malloc allocate memroy from two different areas in memory (New from FreeStore and malloc from Heap (Don't focus on the names they are both basically heaps, those are just there official names from the standard)). If you allocate from one and de-allocate to the other you will messs up the data structures used to manage the memory (there is no gurantee they will use the same structure for memory management).
When you allocate a block like this:
int* x= new int; // 0x32
Memory May look like this: It probably wont since I made this up without thinking that hard.
Memory Value Comment
0x08 0x40 // Chunk Size
0x16 0x10000008 // Free list for Chunk size 40
0x24 0x08 // Block Size
0x32 ?? // Address returned by New.
0x40 0x08 // Pointer back to head block.
0x48 0x0x32 // Link to next item in a chain of somthing.
The point is that there is a lot more information in the allocated block than just the int you allocated to handle memory management.
The standard does not specify how this is done becuase (in C/C++ style) they did not want to inpinge on the compiler/library manufacturers ability to implement the most effecient memory management method for there architecture.
Taking this into account you want the manufacturer the ability to distinguish array allocation/deallocation from normal allocation/deallocation so that it is possable to make it as effecient as possable for both types independantly. As a result you can not mix and match as internally they may use different data structures.
If you actually analyse the memory allocation differences between C and C++ applications you find that they are very different. And thus it is not unresonable to use completely different techniques of memory management to optimise for the application type. This is another reason to prefer new over malloc() in C++ as it will probably be more effecient (The more important reason though will always be to reducing complexity (IMO)).
I have been working on some legacy C++ code that uses variable length structures (TAPI), where the structure size will depend on variable length strings. The structures are allocated by casting array new thus:
STRUCT* pStruct = (STRUCT*)new BYTE[sizeof(STRUCT) + nPaddingSize];
Later on however the memory is freed using a delete call:
delete pStruct;
Will this mix of array new[] and non-array delete cause a memory leak or would it depend on the compiler? Would I be better off changing this code to use malloc and free instead?
Technically I believe it could cause a problem with mismatched allocators, though in practice I don't know of any compiler that would not do the right thing with this example.
More importantly if STRUCT where to have (or ever be given) a destructor then it would invoke the destructor without having invoked the corresponding constructor.
Of course, if you know where pStruct came from why not just cast it on delete to match the allocation:
delete [] (BYTE*) pStruct;
I personally think you'd be better off using std::vector to manage your memory, so you don't need the delete.
std::vector<BYTE> backing(sizeof(STRUCT) + nPaddingSize);
STRUCT* pStruct = (STRUCT*)(&backing[0]);
Once backing leaves scope, your pStruct is no longer valid.
Or, you can use:
boost::scoped_array<BYTE> backing(new BYTE[sizeof(STRUCT) + nPaddingSize]);
STRUCT* pStruct = (STRUCT*)backing.get();
Or boost::shared_array if you need to move ownership around.
Yes it will cause a memory leak.
See this except from C++ Gotchas: http://www.informit.com/articles/article.aspx?p=30642 for why.
Raymond Chen has an explanation of how vector new and delete differ from the scalar versions under the covers for the Microsoft compiler... Here:
http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx
IMHO you should fix the delete to:
delete [] pStruct;
rather than switching to malloc/free, if only because it's a simpler change to make without making mistakes ;)
And, of course, the simpler to make change that I show above is wrong due to the casting in the original allocation, it should be
delete [] reinterpret_cast<BYTE *>(pStruct);
so, I guess it's probably as easy to switch to malloc/free after all ;)
The behaviour of the code is undefined. You may be lucky (or not) and it may work with your compiler, but really that's not correct code. There's two problems with it:
The delete should be an array delete [].
The delete should be called on a pointer to the same type as the type allocated.
So to be entirely correct, you want to be doing something like this:
delete [] (BYTE*)(pStruct);
The C++ standard clearly states:
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
The first alternative is for non-array objects, and the second is for arrays. The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. The result has type void.
In the first alternative (delete object), the value of the operand of delete shall be a pointer to a non-array object [...] If not, the behavior is undefined.
The value of the operand in delete pStruct is a pointer to an array of char, independent of its static type (STRUCT*). Therefore, any discussion of memory leaks is quite pointless, because the code is ill-formed, and a C++ compiler is not required to produce a sensible executable in this case.
It could leak memory, it could not, or it could do anything up to crashing your system. Indeed, a C++ implementation with which I tested your code aborts the program execution at the point of the delete expression.
As highlighted in other posts:
1) Calls to new/delete allocate memory and may call constructors/destructors (C++ '03 5.3.4/5.3.5)
2) Mixing array/non-array versions of new and delete is undefined behaviour. (C++ '03 5.3.5/4)
Looking at the source it appears that someone did a search and replace for malloc and free and the above is the result. C++ does have a direct replacement for these functions, and that is to call the allocation functions for new and delete directly:
STRUCT* pStruct = (STRUCT*)::operator new (sizeof(STRUCT) + nPaddingSize);
// ...
pStruct->~STRUCT (); // Call STRUCT destructor
::operator delete (pStruct);
If the constructor for STRUCT should be called, then you could consider allocating the memory and then use placement new:
BYTE * pByteData = new BYTE[sizeof(STRUCT) + nPaddingSize];
STRUCT * pStruct = new (pByteData) STRUCT ();
// ...
pStruct->~STRUCT ();
delete[] pByteData;
#eric - Thanks for the comments. You keep saying something though, that drives me nuts:
Those run-time libraries handle the
memory management calls to the OS in a
OS independent consistent syntax and
those run-time libraries are
responsible for making malloc and new
work consistently between OSes such as
Linux, Windows, Solaris, AIX, etc....
This is not true. The compiler writer provides the implementation of the std libraries, for instance, and they are absolutely free to implement those in an OS dependent way. They're free, for instance, to make one giant call to malloc, and then manage memory within the block however they wish.
Compatibility is provided because the API of std, etc. is the same - not because the run-time libraries all turn around and call the exact same OS calls.
The various possible uses of the keywords new and delete seem to create a fair amount of confusion. There are always two stages to constructing dynamic objects in C++: the allocation of the raw memory and the construction of the new object in the allocated memory area. On the other side of the object lifetime there is the destruction of the object and the deallocation of the memory location where the object resided.
Frequently these two steps are performed by a single C++ statement.
MyObject* ObjPtr = new MyObject;
//...
delete MyObject;
Instead of the above you can use the C++ raw memory allocation functions operator new and operator delete and explicit construction (via placement new) and destruction to perform the equivalent steps.
void* MemoryPtr = ::operator new( sizeof(MyObject) );
MyObject* ObjPtr = new (MemoryPtr) MyObject;
// ...
ObjPtr->~MyObject();
::operator delete( MemoryPtr );
Notice how there is no casting involved, and only one type of object is constructed in the allocated memory area. Using something like new char[N] as a way to allocate raw memory is technically incorrect as, logically, char objects are created in the newly allocated memory. I don't know of any situation where it doesn't 'just work' but it blurs the distinction between raw memory allocation and object creation so I advise against it.
In this particular case, there is no gain to be had by separating out the two steps of delete but you do need to manually control the initial allocation. The above code works in the 'everything working' scenario but it will leak the raw memory in the case where the constructor of MyObject throws an exception. While this could be caught and solved with an exception handler at the point of allocation it is probably neater to provide a custom operator new so that the complete construction can be handled by a placement new expression.
class MyObject
{
void* operator new( std::size_t rqsize, std::size_t padding )
{
return ::operator new( rqsize + padding );
}
// Usual (non-placement) delete
// We need to define this as our placement operator delete
// function happens to have one of the allowed signatures for
// a non-placement operator delete
void operator delete( void* p )
{
::operator delete( p );
}
// Placement operator delete
void operator delete( void* p, std::size_t )
{
::operator delete( p );
}
};
There are a couple of subtle points here. We define a class placement new so that we can allocate enough memory for the class instance plus some user specifiable padding. Because we do this we need to provide a matching placement delete so that if the memory allocation succeeds but the construction fails, the allocated memory is automatically deallocated. Unfortunately, the signature for our placement delete matches one of the two allowed signatures for non-placement delete so we need to provide the other form of non-placement delete so that our real placement delete is treated as a placement delete. (We could have got around this by adding an extra dummy parameter to both our placement new and placement delete, but this would have required extra work at all the calling sites.)
// Called in one step like so:
MyObject* ObjectPtr = new (padding) MyObject;
Using a single new expression we are now guaranteed that memory won't leak if any part of the new expression throws.
At the other end of the object lifetime, because we defined operator delete (even if we hadn't, the memory for the object originally came from global operator new in any case), the following is the correct way to destroy the dynamically created object.
delete ObjectPtr;
Summary!
Look no casts! operator new and operator delete deal with raw memory, placement new can construct objects in raw memory. An explicit cast from a void* to an object pointer is usually a sign of something logically wrong, even if it does 'just work'.
We've completely ignored new[] and delete[]. These variable size objects will not work in arrays in any case.
Placement new allows a new expression not to leak, the new expression still evaluates to a pointer to an object that needs destroying and memory that needs deallocating. Use of some type of smart pointer may help prevent other types of leak. On the plus side we've let a plain delete be the correct way to do this so most standard smart pointers will work.
If you really must do this sort of thing, you should probably call operator new directly:
STRUCT* pStruct = operator new(sizeof(STRUCT) + nPaddingSize);
I believe calling it this way avoids calling constructors/destructors.
I am currently unable to vote, but slicedlime's answer is preferable to Rob Walker's answer, since the problem has nothing to do with allocators or whether or not the STRUCT has a destructor.
Also note that the example code does not necessarily result in a memory leak - it's undefined behavior. Pretty much anything could happen (from nothing bad to a crash far, far away).
The example code results in undefined behavior, plain and simple. slicedlime's answer is direct and to the point (with the caveat that the word 'vector' should be changed to 'array' since vectors are an STL thing).
This kind of stuff is covered pretty well in the C++ FAQ (Sections 16.12, 16.13, and 16.14):
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.12
It's an array delete ([]) you're referring to, not a vector delete.
A vector is std::vector, and it takes care of deletion of its elements.
You'd could cast back to a BYTE * and the delete:
delete[] (BYTE*)pStruct;
Yes that may, since your allocating with new[] but deallocating with delelte, yes malloc/free is safer here, but in c++ you should not use them since they won't handle (de)constructors.
Also your code will call the deconstructor, but not the constructor. For some structs this may cause a memory leak (if the constructor allocated further memory, eg for a string)
Better would be to do it correctly, as this will also correctly call any constructors and deconstructors
STRUCT* pStruct = new STRUCT;
...
delete pStruct;
It's always best to keep acquisition/release of any resource as balanced as possible.
Although leaking or not is hard to say in this case. It depends on the compiler's implementation of the vector (de)allocation.
BYTE * pBytes = new BYTE [sizeof(STRUCT) + nPaddingSize];
STRUCT* pStruct = reinterpret_cast< STRUCT* > ( pBytes ) ;
// do stuff with pStruct
delete [] pBytes ;
Len: the problem with that is that pStruct is a STRUCT*, but the memory allocated is actually a BYTE[] of some unknown size. So delete[] pStruct will not de-allocate all of the allocated memory.
You're sort of mixing C and C++ ways of doing things. Why allocate more than the size of a STRUCT? Why not just "new STRUCT"? If you must do this then it might be clearer to use malloc and free in this case, since then you or other programmers might be a little less likely to make assumptions about the types and sizes of the allocated objects.
#Matt Cruikshank
You should pay attention and read what I wrote again because I never suggested not calling delete[] and just let the OS clean up. And you're wrong about the C++ run-time libraries managing the heap. If that were the case then C++ would not be portable as is today and a crashing application would never get cleaned up by the OS. (acknowledging there are OS specific run-times that make C/C++ appear non-portable). I challenge you to find stdlib.h in the Linux sources from kernel.org. The new keyword in C++ actually is talking to the same memory management routines as malloc.
The C++ run-time libraries make OS system calls and it's the OS that manages the heaps. You are partly correct in that the run-time libraries indicate when to release the memory however, they don't actually walk any heap tables directly. In other words, the runtime you link against does not add code to your application to walk heaps to allocate or deallocate. This is the case in Windows, Linux, Solaris, AIX, etc... It's also the reason you won't fine malloc in any Linux's kernel source nor will you find stdlib.h in Linux source. Understand these modern operating system have virtual memory managers that complicates things a bit further.
Ever wonder why you can make a call to malloc for 2G of RAM on a 1G box and still get back a valid memory pointer?
Memory management on x86 processors is managed within Kernel space using three tables. PAM (Page Allocation Table), PD (Page Directories) and PT (Page Tables). This is at the hardware level I'm speaking of. One of the things the OS memory manager does, not your C++ application, is to find out how much physical memory is installed on the box during boot with help of BIOS calls. The OS also handles exceptions such as when you try to access memory your application does not have rights too. (GPF General Protection Fault).
It may be that we are saying the same thing Matt, but I think you may be confusing the under hood functionality a bit. I use to maintain a C/C++ compiler for a living...
#ericmayo - cripes. Well, experimenting with VS2005, I can't get an honest leak out of scalar delete on memory that was made by vector new. I guess the compiler behavior is "undefined" here, is about the best defense I can muster.
You've got to admit though, it's a really lousy practice to do what the original poster said.
If that were the case then C++ would
not be portable as is today and a
crashing application would never get
cleaned up by the OS.
This logic doesn't really hold, though. My assertion is that a compiler's runtime can manage the memory within the memory blocks that the OS returns to it. This is how most virtual machines work, so your argument against portability in this case don't make much sense.
#Matt Cruikshank
"Well, experimenting with VS2005, I can't get an honest leak out of scalar delete on memory that was made by vector new. I guess the compiler behavior is "undefined" here, is about the best defense I can muster."
I disagree that it's a compiler behavior or even a compiler issue. The 'new' keyword gets compiled and linked, as you pointed out, to run-time libraries. Those run-time libraries handle the memory management calls to the OS in a OS independent consistent syntax and those run-time libraries are responsible for making malloc and new work consistently between OSes such as Linux, Windows, Solaris, AIX, etc.... This is the reason I mentioned the portability argument; an attempt to prove to you that the run-time does not actually manage memory either.
The OS manages memory.
The run-time libs interface to the OS.. On Windows, this is the virtual memory manager DLLs. This is why stdlib.h is implemented within the GLIB-C libraries and not the Linux kernel source; if GLIB-C is used on other OSes, it's implementation of malloc changes to make the correct OS calls. In VS, Borland, etc.. you will never find any libraries that ship with their compilers that actually manage memory either. You will, however, find OS specific definitions for malloc.
Since we have the source to Linux, you can go look at how malloc is implemented there. You will see that malloc is actually implemented in the GCC compiler which, in turn, basically makes two Linux system calls into the kernel to allocate memory. Never, malloc itself, actually managing memory!
And don't take it from me. Read the source code to Linux OS or you can see what K&R say about it... Here is a PDF link to the K&R on C.
http://www.oberon2005.ru/paper/kr_c.pdf
See near end of Page 149:
"Calls to malloc and free may occur in any order; malloc calls
upon the operating system to obtain more memory as necessary. These routines illustrate some of the considerations involved in writing machine-dependent code in a relatively machineindependent way, and also show a real-life application of structures, unions and typedef."
"You've got to admit though, it's a really lousy practice to do what the original poster said."
Oh, I don't disagree there. My point was that the original poster's code was not conducive of a memory leak. That's all I was saying. I didn't chime in on the best practice side of things. Since the code is calling delete, the memory is getting free up.
I agree, in your defense, if the original poster's code never exited or never made it to the delete call, that the code could have a memory leak but since he states that later on he sees the delete getting called. "Later on however the memory is freed using a delete call:"
Moreover, my reason for responding as I did was due to the OP's comment "variable length structures (TAPI), where the structure size will depend on variable length strings"
That comment sounded like he was questioning the dynamic nature of the allocations against the cast being made and was consequentially wondering if that would cause a memory leak. I was reading between the lines if you will ;).
In addition to the excellent answers above, I would also like to add:
If your code runs on linux or if you can compile it on linux then I would suggest running it through Valgrind. It is an excellent tool, among the myriad of useful warnings it produces it also will tell you when you allocate memory as an array and then free it as a non-array ( and vice-versa ).
Use operator new and delete:
struct STRUCT
{
void *operator new (size_t)
{
return new char [sizeof(STRUCT) + nPaddingSize];
}
void operator delete (void *memory)
{
delete [] reinterpret_cast <char *> (memory);
}
};
void main()
{
STRUCT *s = new STRUCT;
delete s;
}
I think the is no memory leak.
STRUCT* pStruct = (STRUCT*)new BYTE [sizeof(STRUCT) + nPaddingSize];
This gets translated into a memory allocation call within the operating system upon which a pointer to that memory is returned. At the time memory is allocated, the size of sizeof(STRUCT) and the size of nPaddingSize would be known in order to fulfill any memory allocation requests against the underlying operating system.
So the memory that is allocated is "recorded" in the operating system's global memory allocation tables. Memory tables are indexed by their pointers. So in the corresponding call to delete, all memory that was originally allocated is free. (memory fragmentation a popular subject in this realm as well).
You see, the C/C++ compiler is not managing memory, the underlying operating system is.
I agree there are cleaner methods but the OP did say this was legacy code.
In short, I don't see a memory leak as the accepted answer believes there to be one.
Rob Walker reply is good.
Just small addition, if you don't have any constructor or/and distructors, so you basically need allocate and free a chunk of raw memory, consider using free/malloc pair.
ericmayo.myopenid.com is so wrong, that someone with enough reputation should downvote him.
The C or C++ runtime libraries are managing the heap which is given to it in blocks by the Operating System, somewhat like you indicate, Eric. But it is the responsibility of the developer to indicate to the compiler which runtime calls should be made to free memory, and possibly destruct the objects that are there. Vector delete (aka delete[]) is necessary in this case, in order for the C++ runtime to leave the heap in a valid state. The fact that when the PROCESS terminates, the OS is smart enough to deallocate the underlying memory blocks is not something that developers should rely on. This would be like never calling delete at all.