I have a situation in which an allocator for a container concurrently accessed needs to call both placement new and the destructor.
template< class U > void destroy(U* p){
p->~U();
}
as it is I can end up calling the destruction repeatedly. This brought me to think whether something like this should be OK.
std::vector<int>* p = (std::vector<int>*)malloc(sizeof(std::vector<int>));
::new (*p) std::vector<int>(30);
(*p)[10] = 5;
p->~std::vector<int>();
p->~std::vector<int>();
free(p);
I think this will work as long as the destruction of std::vector
sets the data pointer to null or size to zero and when called again there is not a double free.
So, should classes be made such that accidental (or benign) double destruction should be equivalent to a single destruction?
In other words, should destruction be for example an idempotent operation?
(Note for simplicity that the destructor is not virtual in this example)
I find the question is similar to the problem of how to allow a moved class to be destructed later.
Some answers put runtime cost to make the case against supporting double destruction. There are costs, but they are similar to the cost of moving objects. In other words, if it is cheap to move, it is cheap to allow double destruction (if DD is not UB in the first place for other reasons, such as the standard).
To be specific:
class dummyvector{
int* ptr;
public:
dummyvector() : ptr(new int[10]){}
dummyvector(dummyvector const& other) = delete; // for simplicity
dummyvector(dummyvector&& other) : ptr(other.ptr){
other.ptr = nullptr; // this makes the moved object unusable (e.g. set) but still destructable
}
dummyvector& operator=(dummyvector const&) = delete; // for simplicity
void set(int val){for(int i = 0; i != 10; ++i) ptr[i]=val;}
int sum(){int ret = 0; for(int i = 0; i != 10; ++i) ret += ptr[i]; return ret;}
~dummyvector(){
delete[] ptr;
ptr = nullptr; // this is the only extra cost for allowing double free (if it was not UB)
// ^^ this line commented would be fine in general but not for double free (not even in principle)
}
};