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?
My initial thought was that it is undefined behavior.
Footnote 73 reads, “This implies that an object cannot be deleted using a pointer of type
void*because there are no objects of typevoid“.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:
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[].
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.