Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I new[], then cast the pointer, then delete[] safely with built-in types in C++?

In my code I have effectively the following:

wchar_t* buffer = new wchar_t[size];
// bonus irrelevant code here
delete[] reinterpret_cast<char*>( buffer );

Types in question are all built-in and so they have trivial destructors. In VC++ the code above works allright - new[] just allocates memory, then delete[] just frees it.

Is it acceptable in C++? Is it undefined behaviour?

like image 675
sharptooth Avatar asked Jan 26 '10 15:01

sharptooth


People also ask

When to use delete [] and delete?

delete is used for one single pointer and delete[] is used for deleting an array through a pointer.

When would you use the delete [] syntax?

When you have an array of objects you need to use delete[] as shown in the example below. std::string *myName=new std::string; std::string *myStrings=new std::string[10]; delete myName; //deletes an object delete[] myString; //deletes an array of object.

How does delete [] work in C?

Master C and Embedded C Programming- Learn as you goDelete[] operator is used to deallocate that memory from heap. New operator stores the no of elements which it created in main block so that delete [] can deallocate that memory by using that number.

What is the difference between delete and delete square bracket in C Plus Plus?

What is the difference between delete and delete[] in C++? Explanation: delete is used to delete a single object initiated using new keyword whereas delete[] is used to delete a group of objects initiated with the new operator.


3 Answers

My initial thought was that it is undefined behavior.

5.3.5/3: "In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.73).

Footnote 73 reads, "This implies that an object cannot be deleted using a pointer of type void* because there are no objects of type void".

Arguably the object in your example doesn't have a dynamic type, since the definition of "dynamic type" at 1.3.3 mentions "most derived object", and the definition of "most derived object" at 1.8/4 is talking about objects of class type. So I kept looking:

5.2.10/3: "[reinterpret_cast] might, or might not, produce a representation different from the original value"

5.3.5/2: "The value of the operand of delete shall be the pointer value which resulted from a previous array new-expression".

I'm not sure whether a reinterpret_cast results in the same pointer value as was input, or not. Possibly it's cleared up by some other bit of the standard which I haven't found yet. I would not call this code "OK" without finding something to definitively state that if you reinterpret_cast a pointer, the result is the same "pointer value" as before, so that by passing it to delete[] you are passing "the pointer value" from new[].

5.2.10/7: "Except that casting [between certain pointer types] and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified".

This looks like bad news to me - it conspicuously doesn't say that the cast yields the same value, only that the pair of casts over and back, yields the same value. This suggests to me that the single cast is allowed to yield a different value, but it is only suggestive, not explicit. This is the usual problem with the rule that "if the standard doesn't state the behavior, then the behavior is undefined". Just because it doesn't state it in any of the paragraphs I can find using the index, doesn't mean it doesn't state it somewhere else...

We know that in practice we can cast things to unsigned char* in order to inspect their bytes, or void* to copy PODs using memcpy, so there must be some casts guaranteed to create aliases. You might think that if your implementation does create aliases with certain casts, then you're passing in the "same value" you got from new[]. But I'm still not sure that's good enough for delete[]. I think I'm missing something important.

like image 172
Steve Jessop Avatar answered Sep 29 '22 15:09

Steve Jessop


It is undefined behaviour because delete[] invokes the wrong destructor. However, wchar_t and char are PODs, so they have no dedicated destructor and all delete[] does is calling the heap implementation to free up the pointer. Therefore, it is most likely to work, no byte is lost. But strictly speaking it is still undefined.

like image 31
Alexander Gessler Avatar answered Sep 29 '22 17:09

Alexander Gessler


At least as I'd read it, you have a static type (the type of the pointer) that differs from the dynamic type (the real type of the object it points at). That being the case, the second sentence of §5.3.5/3 applies:

In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

Edit: Since what you apparently want is to allocate a buffer of "raw" memory instead of an array of objects, I'd advise using ::operator new instead of new[]. In this case, what you're doing is clearly defined, and also gives the reader a clear indication of intent.

like image 28
Jerry Coffin Avatar answered Sep 29 '22 15:09

Jerry Coffin