Reputation: 23
Does anyone know a C++ delete procedure that is safe for both placement new and for regular new?
Object* regular = new Object();
delete_procedure(regular);
void* buf = ::new(sizeof(Object));
Object* placement = new(buf) Object();
delete_procedure(placement);
This function seems to work, but I can't figure out if it's actually safe for both instances (it's the standard method of deleting placement new).
delete_procedure(Object* obj){ // Not sure if safe for regular new
obj->~Object();
::delete(obj);
}
Upvotes: 0
Views: 265
Reputation: 275385
No, because of arrays and details. Sure, because these problems probably don't matter in your code base.
All deletes are either type specific deletes, or:
The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new(size_t) or operator new(size_t, std::nothrow_t).
from http://en.cppreference.com/w/cpp/memory/new/operator_delete
This means passing memory allocated by new[](size_t)
to delete(void*)
is UB, and new[](size_t)
to delete[](void*)
is UB.
Second, users are free to replace new/delete on a global or per-class basis.
Third:
void delete_procedure(Object* obj){
obj->~Object();
::operator delete((void*)obj);
}
you'll want to cast to void pointer there and use operator delete.
Forth, the pointer passed to delete_procedure
must be the pointer generated by new T
or ::new( ::new(sizeof(T)) ) T
; it cannot be a pointer to a derives subobject, as its value as a void*
may differ.
If T* pt
is dynamic castable, dynamic_cast<void*>( pt )
will reconstruct that void*
. So this is less of a barrier than it seems. Remember to do the cast before destroying the object!
void delete_procedure_dynamic(Object* obj){
void* ptr=dynamic_cast<void*>(obj);
obj->~Object();
::operator delete(ptr);
}
and use SFINAE/tag dispatching to dispatch between the dynamic and non-dynamic versions.
Fifth, high alignment types need work to handle. They use different new and delete. I am uncertain how dynamic casting and over aligned derived types would interact, but probably you don't have to care.
But new T
calls ::new(size_t)`` then constructs an object there.
operator delete(void*)must be fed memory produced by
::new(size_t). Destroying an object creates by
new Tis legal via
.~T()`. So I see nothing fundamentally broken.
In practice, what I might do is override "normal" new to follow the same pattern as your extra storage new (and allocate the block via new(size_t)
) to keep things simple. You are in arcane territory, why not make things uniform.
Upvotes: 1
Reputation: 372784
I don't believe there's any unified way of doing this without introducing some extra flags to mark things. The C++ philosophy is "you need to keep track of how you allocated things and ensure they're all destroyed properly," and it does this for efficiency purposes. Think about delete[]
versus delete
. There could be a unified delete
keyword that cleans up any block of memory, but that would incur a performance overhead because of the cost of determining which deallocation routine needs to be invoked. Or think about virtual destructors: C++ could say that delete
always does some kind of type introspection, but that would add overhead to all object types, much of it unnecessarily.
C++'s philosophy is "don't pay for what you don't use," and so if you want to build something unified, you'll need to set up some extra infrastructure to track what sorts of deletion routine you need to do.
Upvotes: 3