C++ C++;在不释放内存的情况下调用析构函数

C++ C++;在不释放内存的情况下调用析构函数,c++,C++,让我们假设,无论出于什么原因,我想在不释放内存的情况下调用对象的析构函数。我知道这在obj->~Type()中是可行的,但是假设我有一个void*,并且不知道静态的类型。我想我需要两个指针,一个用于对象,一个用于析构函数 然而,我很好奇,在这种情况下,是否有可能只用一个指针就可以逃脱惩罚。假设我可以保证对象将有一个虚拟析构函数,并且它最多从一个基类派生。是否可以通过v形台到达析构函数?以符合标准的方式(可能不)这是可行的吗?让我们假设一个合理的编译器将dtor最后一个放在vtable中。毕竟,很

让我们假设,无论出于什么原因,我想在不释放内存的情况下调用对象的析构函数。我知道这在
obj->~Type()
中是可行的,但是假设我有一个
void*
,并且不知道静态的类型。我想我需要两个指针,一个用于对象,一个用于析构函数


然而,我很好奇,在这种情况下,是否有可能只用一个指针就可以逃脱惩罚。假设我可以保证对象将有一个虚拟析构函数,并且它最多从一个基类派生。是否可以通过v形台到达析构函数?以符合标准的方式(可能不)这是可行的吗?

让我们假设一个合理的编译器将dtor最后一个放在vtable中。毕竟,很少调用dtor—每个对象只调用一次。您无法找到它,因为不同的vtable具有不同的长度。

让我们假设一个合理的编译器将dtor最后一个放在vtable中。毕竟,很少调用dtor—每个对象只调用一次。您找不到它,因为不同的vtable具有不同的长度。

您无法获得析构函数的地址。引用C++17标准:

不得使用析构函数的地址

-参见[class.dtor]/2

双指针解 然而,您的双指针方法是有效的。请参见以下示例():

基本上,这和前面的方法是一样的。指针
a
被lambda捕获,因此它知道要销毁哪个
Apple

如前所述,在创建
d
时,您必须了解
Apple
。它在lambda中。如果调用
d()
,则不必知道类型

具有一个指针的解决方案(使用公共基类) 显然,您可以调用dtor。如果
水果::~Fruit
虚拟的,则通过
水果*
指针执行
苹果
(否则为虚拟的)。与双指针解决方案类似,当您构建一个
Apple
对象以供以后存储和销毁时,您必须知道其类型(
Fruit*f=new Apple()
),而当您销毁它时,您不必知道它(
f->~Fruit()

这里的
f
是一个指针,但最后使用了第二个指针vfptr(即虚拟函数指针),它指向一系列函数指针,其中一个是指向
~Apple
的指针。因此,对
f->~Fruit()
取消了三个指针的引用:

  • f
  • vfptr
  • 指向
    ~Apple
    的指针
具有一个指针的解决方案(无公共基类) 这是不可能的。调用析构函数是汇编中的
调用
指令。为此,您必须有两个指针:

  • 要传递的参数(
    指针),以及
  • 要呼叫的地址(dtor.)

因此,即使有人有一个单指针解决方案,它也会通过某种间接方式包含第二个指针。

您无法获得析构函数的地址。引用C++17标准:

不得使用析构函数的地址

-参见[class.dtor]/2

双指针解 然而,您的双指针方法是有效的。请参见以下示例():

基本上,这和前面的方法是一样的。指针
a
被lambda捕获,因此它知道要销毁哪个
Apple

如前所述,在创建
d
时,您必须了解
Apple
。它在lambda中。如果调用
d()
,则不必知道类型

具有一个指针的解决方案(使用公共基类) 显然,您可以调用dtor。如果
水果::~Fruit
虚拟的,则通过
水果*
指针执行
苹果
(否则为虚拟的)。与双指针解决方案类似,当您构建一个
Apple
对象以供以后存储和销毁时,您必须知道其类型(
Fruit*f=new Apple()
),而当您销毁它时,您不必知道它(
f->~Fruit()

这里的
f
是一个指针,但最后使用了第二个指针vfptr(即虚拟函数指针),它指向一系列函数指针,其中一个是指向
~Apple
的指针。因此,对
f->~Fruit()
取消了三个指针的引用:

  • f
  • vfptr
  • 指向
    ~Apple
    的指针
具有一个指针的解决方案(无公共基类) 这是不可能的。调用析构函数是汇编中的
调用
指令。为此,您必须有两个指针:

  • 要传递的参数(
    指针),以及
  • 要呼叫的地址(dtor.)

因此,即使有人有一个单指针解决方案,它也会通过某种间接方式包含第二个指针。

我觉得你的方法不错。这将是很好的看到实际的代码,以确保。可移植的方式?绝对不是。对您的特定实现有效的方法?可能,这取决于它如何布置vtables。如果您非常关心运行时性能,您应该愿意用一些编译时间来换取它(使用模板,这样您就不会被
void*
s所束缚)。您的意思是每个对象都派生自一个基类(无MI)还是所有对象共享相同的基类(因此
void*
是错误的类型)你为什么要这么做?为什么要有一个C++对象,如果你想独立于对象管理它的内存呢?你说它“最多会从一个基类派生”,但是你会说“它们没有一个公共基类”。这似乎是直接冲突。我觉得你的方法不错。这将是很好的看到实际的代码,以确保。可移植的方式?绝对不是。对您的特定实现有效的方法?可能吧,德潘丁
class Apple {};


struct Destructor {
public:
    template <class T>
    Destructor (const T* object) :
        object (object),
        dtor   ([] (const void* o) { static_cast<const T*> (o)->~T (); })
    {
    }

    void Call ()
    {
        dtor (object);
    }

private:
    const void*  object;
    void (*dtor) (const void*);
};


int main ()
{
    Apple* a = new Apple ();

    Destructor d (a);
    d.Call ();
}
#include <functional>

class Apple {};


int main ()
{
    Apple* a = new Apple ();

    std::function<void ()> d = [=] () { a->~Apple (); };
    d ();
}
struct Fruit { virtual ~Fruit () {} };
struct Apple : Fruit {};