C++20引入了“摧毁
这到底是什么以及何时有用?
operator delete
”:这是一种新的operator delete
重载形式,它接受一个标签类型std::destroying_delete_t
参数。这到底是什么以及何时有用?
operator delete
”:这是一种新的operator delete
重载形式,它接受一个标签类型std::destroying_delete_t
参数。operator delete
函数之前被调用。随着 C++20 引入了可销毁的 operator delete
,operator delete
可以直接调用析构函数。下面是一个非销毁与销毁 operator delete
的简单示例:#include <iostream>
#include <new>
struct Foo {
~Foo() {
std::cout << "In Foo::~Foo()\n";
}
void operator delete(void *p) {
std::cout << "In Foo::operator delete(void *)\n";
::operator delete(p);
}
};
struct Bar {
~Bar() {
std::cout << "In Bar::~Bar()\n";
}
void operator delete(Bar *p, std::destroying_delete_t) {
std::cout << "In Bar::operator delete(Bar *, std::destroying_delete_t)\n";
p->~Bar();
::operator delete(p);
}
};
int main() {
delete new Foo;
delete new Bar;
}
输出结果:
In Foo::~Foo()
In Foo::operator delete(void *)
In Bar::operator delete(Bar *, std::destroying_delete_t)
In Bar::~Bar()
关键信息:
operator delete
必须是一个类成员函数。operator delete
,一个销毁函数将始终优先于非销毁函数。operator delete
签名之间的区别在于前者接收一个void *
,而后者接收一个指向要删除对象类型的指针和一个虚拟参数std::destroying_delete_t
。operator delete
一样,销毁operator delete
也可以采用可选的std::size_t
和/或std::align_val_t
参数,以相同的方式。它们的含义与以前相同,并且在虚拟参数std::destroying_delete_t
之后。operator delete
运行之前不会调用析构函数,因此预计需要自己调用析构函数。这也意味着对象仍然有效,在进行操作之前可以检查对象。operator delete
时,通过基类指针调用派生对象的delete
而没有虚拟析构函数是未定义行为。通过给基类提供销毁operator delete
可以使其实现使用其他方式确定要调用的正确析构函数,从而使其安全和定义良好。销毁operator delete
的使用场景在P0722R1中详细说明。这里是一个简短的摘要:
operator delete
允许具有变量大小数据的类保留大小为delete
的性能优势。这通过在对象内部存储大小,并在调用析构函数之前在operator delete
中检索它来实现。operator delete
来删除此类对象,以便可以确定分配的正确起始地址。以下是第三个用例的示例:
#include <iostream>
#include <new>
struct Shape {
const enum Kinds {
TRIANGLE,
SQUARE
} kind;
Shape(Kinds k) : kind(k) {}
~Shape() {
std::cout << "In Shape::~Shape()\n";
}
void operator delete(Shape *, std::destroying_delete_t);
};
struct Triangle : Shape {
Triangle() : Shape(TRIANGLE) {}
~Triangle() {
std::cout << "In Triangle::~Triangle()\n";
}
};
struct Square : Shape {
Square() : Shape(SQUARE) {}
~Square() {
std::cout << "In Square::~Square()\n";
}
};
void Shape::operator delete(Shape *p, std::destroying_delete_t) {
switch(p->kind) {
case TRIANGLE:
static_cast<Triangle *>(p)->~Triangle();
break;
case SQUARE:
static_cast<Square *>(p)->~Square();
}
::operator delete(p);
}
int main() {
Shape *p = new Triangle;
delete p;
p = new Square;
delete p;
}
它会打印出这个:
In Triangle::~Triangle()
In Shape::~Shape()
In Square::~Square()
In Shape::~Shape()
(注意:GCC 11.1及更早版本在启用优化时将错误调用Triangle ::〜Triangle()
而不是Square ::〜Square()
。请参见错误#91859的评论2。)delete
运算符的有效操作数的措辞进行进一步更改。 - Ben Voigt