Reputation: 8542
I finally got around to trying placement new to create an efficient dynamic array. the purpose is to understand how it works, not to replace class vector. The constructor works. A block is allocated but uninitialized. As each element is added, it is initialized. But I don't see how to use placement delete to call the destructor on only those elements that exist. Can anyone explain that one? This code works for allocating the elements one by one as the array grows, but the delete is not right.
template<typename T>
class DynArray {
private:
uint32_t capacity;
uint32_t size;
T* data;
void* operator new(size_t sz, T* place) {
return place;
}
void operator delete(void* p, DynArray* place) {
}
public:
DynArray(uint32_t capacity) :
capacity(capacity), size(0), data((T*)new char[capacity*sizeof(T)]) {}
void add(const T& v) {
new(data+size++) T(v);
}
~DynArray() {
for (int i = 0; i < size; i++)
delete (this) &data[i];
delete [] (char*)data;
}
};
Upvotes: 3
Views: 2046
Reputation: 24738
A placement delete
doesn't make much sense since the destructor already does what a placement delete
is supposed to do.
An ordinary delete
calls the destructor and then releases the memory that was allocated for the object with new
. However, unlike an ordinary new
, a placement new
does not allocate memory, it only initialises it. Therefore, a placement delete
would only have to call the destructor of the object to be "deleted".
All you need is to call the destructor of each object of the array directly:
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
}
Since C++17 you can also use the function template std::destroy
instead of directly calling the destructor:
~DynArray() {
auto first = std::addressof(data[0]);
auto last = std::next(first, size);
std::destroy(first, last);
}
Upvotes: 3
Reputation: 7838
You actually found the only case (at least that I'm aware of) where you want to invoke the destructor manually:
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
delete [] (char*)data;
}
Combined with a trivial class and main
, you should get the expected results:
struct S {
~S() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};
int main() {
DynArray<S> da{10};
da.add(S{});
return 0;
}
Note that you see the destructor called twice since DynArray
takes objects by const
reference, thus it has a temporary.
$./a.out
S::~S()
S::~S()
Upvotes: 1