如何将析构函数分配给指针

How to assign a destructor to a pointer?

本文关键字:指针 分配 析构函数      更新时间:2023-10-16

我正在写一个内存管理库,需要显式调用析构函数,在我的设计中,我有一个指针指向对象的析构函数方法,我写的代码是这样的:

void (*p)() = foo.~Foo;

但我有

错误:无法从类型"void(Foo::(((noexcept"转换"Foo::~Foo"键入"void(*(((">

我尝试了其他格式,如void (Foo:: (*p))() noexcept = foo.~Foo;,但失败了。

那么,将析构函数赋值给指针的正确方法是什么呢?

编辑:在运行时,我的代码不知道堆中的类型,所以我不能使用foo~Foo((。我需要一个适用于所有析构函数的生成指针,这可能吗?

解决方案:使用模板包装器

不允许获取析构函数的地址。

然而,你可以制作一个非常简单的模板函数,并使用它:

template<class T>
void destruct(const T* x) {
x->~T();
}

现在,只需从以下位置获取指针:

destruct<Foo>

如果需要绑定到一个实际对象,可以使用例如std::bind(或lambda(:

std::bind(&destruct<Foo>, foo_ptr);

请注意,一旦它被绑定,就无法将其转换为原始函数指针。

对不起,您不能。不允许按照[class.dtor]/2:获取析构函数的地址

析构函数用于销毁其类类型的对象不得获取析构函数的地址析构函数可以为constvolatileconst volatile对象调用。constvolatile语义([dcl.type.cv](不应用于对象遭到破坏。当的析构函数最派生的对象开始。

我需要一个适用于所有析构函数的生成指针,这可能吗?

不,不是。就像它不会与任何其他成员功能一样。

要在对象上调用函数,您需要知道该对象的类型。

而且,由于您不能获取析构函数的地址,您甚至不能在"数据库"中存储/注册析构函数。然而,正如Paul所展示的,你可以存储一个函子来完成这项工作。为每个使用中的对象注册这些会有点难看,但当你试图重新发明类型系统时,就会发生这种情况!

我强烈建议不要进行类型擦除(不如进行一些不错的继承?(,不要自己调用析构函数。

请记住,析构函数当然是一个成员函数,因此您需要两个指针:一个用于对象,另一个用于成员函数(本例中为析构函数(的偏移量。

要获取对象的地址很简单,只需使用std::addressof()即可。

但是,要到达析构函数,您需要一个包装函数来调用给定对象地址的析构函数。因为您不能获取析构函数的地址。

因此,使用Herb Sutter建议的东西(感谢@LightnessRacesinOrbit和@Croolman的评论(:

[](const void* x) { static_cast<const Foo*>(x)->~Foo(); }