销毁 Incomplete 类型的对象

Qwe*_*pal 2 c++

我已经阅读了关于该主题的其他 stackoverflow 问题,但我真的对不完整的类型和这个 C++ 规范段落 §5.3.5/5 感到困惑:

如果被删除的对象在删除点具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。

举个例子, .h :

template<class T> class my_scoped_ptr
{
private:
    T *t;
public:
    my_scoped_ptr(T * _t) : t(_t) {}
    ~my_scoped_ptr()  {
        typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
        (void) sizeof(type_must_be_complete);
        delete t;
    }
};

class Holder
{
public:
    Holder();
    ~Holder();
private:
    class Impl;
    my_scoped_ptr<Impl> _mptr;
};
Run Code Online (Sandbox Code Playgroud)

.cpp

class Holder::Impl {};
Holder::Holder() : _mptr(new Impl) {}
Holder::~Holder() {}
Run Code Online (Sandbox Code Playgroud)

类 Holder 的非内联析构函数是如何突然让 Impl 完成的?为什么默认析构函数不足以使类完整?为什么 shared_ptr 在不需要析构函数的情况下工作得很好?

Igo*_*nik 5

这都是关于my_scoped_ptr<Impl>::~my_scoped_ptr.

当您不提供用户定义的析构函数时,默认Holder的析构函数会在处理类的定义后立即定义——基本上,它等同于在类中定义析构函数:

class Holder {
  // ... 
  ~Holder() {}
};
Run Code Online (Sandbox Code Playgroud)

这个析构函数需要销毁_mptr成员,所以此时~my_scoped_ptr也被实例化了,虽然Impl还没有完成。

当您在头文件中显式声明析构函数并在 .cpp 文件中定义时,实例化~my_scoped_ptr发生在该定义点 - 到那时,Impl已经完成。

std::shared_ptr通过在运行时,在它的构造函数中,在它第一次传递原始指针的地方捕获删除器,并将它存储在控制块中,来解决这个问题。你甚至可以赋值std::shared_ptr<Derived>给std::shared_ptr<Base>,后者最终会调用正确的析构函数,即使是非虚拟的。std::shared_ptr可以使用这个技巧,因为它无论如何都需要分配额外的存储空间(用于引用计数等),所以它已经有些重量级了。std::unique_ptr另一方面my_scoped_ptr,出于所有相同的原因,显示出与您相同的问题。