如何在动态数组中的某些对象上调用析构函数
how to call destructor on some of the objects in a Dynamic Array
我终于抽出时间尝试使用 placement new 来创建高效的动态数组。目的是了解它是如何工作的,而不是替换 class 向量。构造函数工作。块已分配但未初始化。添加每个元素时,都会对其进行初始化。但我看不到如何使用 placement delete 仅在那些存在的元素上调用析构函数。任何人都可以解释一下吗?此代码适用于随着数组的增长逐一分配元素,但删除不正确。
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;
}
};
您实际上找到了唯一一种您想手动调用析构函数的情况(至少我知道):
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
delete [] (char*)data;
}
结合一个简单的 class 和 main
,你应该得到预期的结果:
struct S {
~S() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};
int main() {
DynArray<S> da{10};
da.add(S{});
return 0;
}
请注意,您看到析构函数调用了两次,因为 DynArray
通过 const
引用获取对象,因此它有一个临时的。
$./a.out
S::~S()
S::~S()
放置 delete
没有多大意义,因为析构函数已经做了放置 delete
应该做的事情。
一个普通的delete
调用析构函数,然后释放为new
对象分配的内存。但是,与普通的 new
不同,放置 new
不分配内存,它只是初始化它。因此,放置 delete
只需调用对象的析构函数即可 "deleted"。
你只需要直接调用数组的每个对象的析构函数:
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
}
从 C++17 开始,您还可以使用函数模板 std::destroy
而不是直接调用析构函数:
~DynArray() {
auto first = std::addressof(data[0]);
auto last = std::next(first, size);
std::destroy(first, last);
}
我终于抽出时间尝试使用 placement new 来创建高效的动态数组。目的是了解它是如何工作的,而不是替换 class 向量。构造函数工作。块已分配但未初始化。添加每个元素时,都会对其进行初始化。但我看不到如何使用 placement delete 仅在那些存在的元素上调用析构函数。任何人都可以解释一下吗?此代码适用于随着数组的增长逐一分配元素,但删除不正确。
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;
}
};
您实际上找到了唯一一种您想手动调用析构函数的情况(至少我知道):
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
delete [] (char*)data;
}
结合一个简单的 class 和 main
,你应该得到预期的结果:
struct S {
~S() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};
int main() {
DynArray<S> da{10};
da.add(S{});
return 0;
}
请注意,您看到析构函数调用了两次,因为 DynArray
通过 const
引用获取对象,因此它有一个临时的。
$./a.out
S::~S()
S::~S()
放置 delete
没有多大意义,因为析构函数已经做了放置 delete
应该做的事情。
一个普通的delete
调用析构函数,然后释放为new
对象分配的内存。但是,与普通的 new
不同,放置 new
不分配内存,它只是初始化它。因此,放置 delete
只需调用对象的析构函数即可 "deleted"。
你只需要直接调用数组的每个对象的析构函数:
~DynArray() {
for (int i = 0; i < size; i++)
data[i].~T();
}
从 C++17 开始,您还可以使用函数模板 std::destroy
而不是直接调用析构函数:
~DynArray() {
auto first = std::addressof(data[0]);
auto last = std::next(first, size);
std::destroy(first, last);
}