3

Assume I want to allocate only 256 bytes memory blocks

char * memory = new char[256];

than I use placement new to create a FooBar object (sizeof(Foobar)<=256)

FooBar * obj = new (memory) FooBar();

does

delete obj; //this also calls the destructor of FooBar

delete all the 256 bytes of memory?

Does the standard guarantee that the whole "memory" buffer is deallocated by just "deleting obj"? Or it is based on the type "FooBar" and therefore this operation has undefined behaviour?

Assumption: FooBar is the only object in the memory buffer.

This is not duplicate question, please first understand the question. It is not immediately evident what this code does.

icedwater
  • 4,701
  • 3
  • 35
  • 50
CoffeDeveloper
  • 7,961
  • 3
  • 35
  • 69
  • no. This is not a question about placement new. I'm asking if is valid deleting "obj" as alias for "memory". If the standard says that is possible then this will be tremendously usefull for me (and probably also for others). – CoffeDeveloper Jul 08 '13 at 04:50
  • 2
    Oh yes it is. Cared to read the answer until its end? "You should not deallocate every object that is using the memory buffer. Instead you should `delete[]` only the original buffer." - Also, the third comment under the answer: "Strictly, it's undefined behaviour to call delete[] on the original char buffer." –  Jul 08 '13 at 04:51
  • I'm not calling delete[] on the original buffer infact. – CoffeDeveloper Jul 08 '13 at 04:53
  • 2
    I don't mind if you do or don't - that answer answers your question. –  Jul 08 '13 at 04:54
  • It's not undefined there's a thin difference. Actually that is working, the custom allocator just receive as parameter "a memory location" so does not know that I'm deletin "FooBar". "delete obj" call's FooBar destructor, then pass the memory location to the allocator. FooBar is correctly destroyed, then memory released because the size of 256 bytes is stuff for the allocator that has an header right before the 256 bytes buffer. Thhat's work, but seems a bit strange to me. Does the standard allows that? It seems yes, but that's surprising! – CoffeDeveloper Jul 08 '13 at 05:00
  • Of course that work just because FooBar is aligned with the "memory" buffer and because there are no other objects around. – CoffeDeveloper Jul 08 '13 at 05:02
  • 1
    @DarioOO Not sure if it's just the example or not, but when creating objects in your own buffer, watch out for alignment. ie. From your example FooBar * obj = new (&memory[15]) FooBar(); will slow your program down since any values greater than sizeof char in your object will not be correctly aligned. – Twifty Jul 08 '13 at 05:33
  • 1
    yes placement new helps to align objects to memory, in this case I aligned the object to &memory[0] for simplicity. By the way the standard does not allow my code (even if tested and working on MSVC and GCC). – CoffeDeveloper Jul 08 '13 at 05:44
  • @DarioOO "placement new helps to align objects to memory" Are you sure? you're telling placement new to initialize an instance of an object at the address you specify. It's up to you to make sure it's aligned. All it really does is call the c'tor. Also I see no reason why your code won't work, it is 'standard'. – Twifty Jul 08 '13 at 05:52
  • @Waldermort Using `delete` with a pointer that has not been created by `new` is fairly 'non-standard'. (Even if it would be valid to delete the memory through another pointer there is still the problem that the allocation was done using `new[]` while `delete` is used instead of `delete[]`.) – Pixelchemist Jul 08 '13 at 05:57
  • @Pixelchemist I was talking in reference to his using placement new on his own buffer. Of course, freeing the underlying memory without first freeing the objects is a big NO NO. – Twifty Jul 08 '13 at 06:00
  • 2
    @Waldermort Ah, ok - but I think DarioOO was talking about the delete thing when he wrote "_the standard does not allow my code_". – Pixelchemist Jul 08 '13 at 06:02

2 Answers2

6

The C++ standard tells you why it is undefined what you're doing. It may be the case that the deallocation that is invoked by delete uses the prepended size info of the allocated block and deallocates it properly but you can't rely on that.

§5.3.5 Delete

The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression. delete-expression:

  • ::delete cast-expression
  • ::delete [ ] cast-expression

The first alternative is for non-array objects, and the second is for arrays. Whenever the delete keyword is immediately followed by empty square brackets, it shall be interpreted as the second alternative. [...]

That to be said, now we come to the more interesting part:

2 [...] In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined. [...]

  1. The pointer to your object was not created by the new expression but only object construction was done via placement new.
  2. The pointer at the address obj (which should, cast to void* be the same as memory cast to void* but afaik you can't even rely on that) points to was allocated using new[] so using delete[] is mandatory.

See those related questions:


If you want to have a pre-allocated storage for several objects of the same type: consider using std::vector<FooBar>::reserve().

emplace_back() or push_back() will then do in-place construction of the objects.

Community
  • 1
  • 1
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
  • so undefined even if tests are working on 2 different compilers :/ ok thanks – CoffeDeveloper Jul 08 '13 at 05:40
  • 1
    @DarioOO Yeah. I think the allocation using the prepended info-block that stores the allocated bytes is rather common and I think the allocator that deallocates the memory is the same for `delete` and `delete[]` which just deallocates `size_from_info()+size_of_info()` starting at `ptr-size_of_info()`. See [this answer](http://stackoverflow.com/questions/16624438/c-allocates-abnormally-large-amout-memory-for-variables/16624732#16624732) for an illustration. But even if it is common that doesn't mean you can rely on that in any "real world code". It's nice to know for some play-around stuff... – Pixelchemist Jul 08 '13 at 05:44
5

That is indeed undefined behaviour, the correct way of doing it is to call the destructor of every object allocated in that block of memory explicitly and then deallocate the memory block itself.

obj->~FooBar();
delete[] memory;

Remember that placement new just construct the object, it doesnt allocate the memory, so the object shouldnt free it. If YOU allocate the memory, you should free it, if you constructed the object, you should only deconstruct it.

AngelCastillo
  • 2,385
  • 2
  • 18
  • 26