I want to reset an object. Can I do it in the following way?
anObject->~AnObject();
anObject = new(anObject) AnObject();
// edit: this is not allowed: anObject->AnObject();
This code is obviously a subset of typical life cycle of an object allocated by in placement new:
AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); // My step 2.
// ...
anObject->~AnObject(); // My step 1.
free(anObject)
// EDIT: The fact I used malloc instead of new doesn't carry any meaning
The only thing that's changed is the order of constructor and destructor calls.
So, why in the following FAQ all the threatening appear?
[11.9] But can I explicitly call a destructor if I've allocated my object with new?
FAQ: You can't, unless the object was allocated with placement new. Objects created by new must be deleted, which does two things (remember them): calls the destructor, then frees the memory.
FQA: Translation: delete is a way to explictly call a destructor, but it also deallocates the memory. You can also call a destructor without deallocating the memory. It's ugly and useless in most cases, but you can do that.
The destructor/constructor call is obviously normal C++ code. Guarantees used in the code directly result from the in placement new guarantees. It is the core of the standard, it's rock solid thing. How can it be called "dirty" and be presented as something unreliable?
Do you think it's possible, that the in-placement and non-in-placement implementation of new are different? I'm thinking about some sick possibility, that the regular new can for example put size of the memory block allocated before the block, which in-placement new obviously would not do (because it doesn't allocate any memory). This could result in a gap for some problems... Is such new() implementation possible?
You cannot call the constructor in the manner indicated by you. Instead, you can do so using placement-new (like your code also indicates):
This code is guaranteed to be well-defined if the memory location is still available – as it should be in your case.
(I've deleted the part about whether this is debatable code or not – it's well-defined. Full stop.)
By the way, Brock is right: how the implementation of
delete
isn't fixed – it is not the same as calling the destructor, followed byfree
. Always pair calls ofnew
anddelete
, never mix one with the other: that's undefined.If your object has sensible assignment semantics (and correct operator=), then *anObject = AnObject() makes more sense, and is easier to understand.
Note that they're not
malloc
andfree
that are used, butoperator new
andoperator delete
. Also, unlike your code, by using new you're guaranteeing exception safety. The nearly equivalent code would be the following.The reset you're proposing is valid, but not idiomatic. It's difficult to get right and as such is generally frowned upon and discouraged.
Why not implement a Clear() method, that does whatever the code in the body of the destructor does? The destructor then just calls Clear() and you call Clear() directly on an object to "reset it".
Another option, assuming your class supports assignment correctly:
I use this pattern for resetting std::stack instances, as the stack adaptor does not provide a clear function.