3

假设我们有一个base类和一个derived. 所以:

class base {
     protected:
          ~base(){
                //...
          }
     // ...
};

class derived : public base {
     // ...
};

现在说我们有这个代码使用上面的类和一个智能指针类:

SmartPointer<base> bptr(new derived());
delete bptr;

我知道它会derived通过调用 的析构函数来防止对对象进行切片derived,但是它怎么知道这样做呢?存储在智能指针中的引用不会是 type 的引用base*吗?它是否遍历某种层次结构树,将该指针转换为derived*然后调用删除?或者还有什么我不知道的?

该实现被认为是线程安全的、非侵入式的和引用计数。

的,您看到的类类似于我正在测试的类。显然有一种方法可以使用这些给定的课程来做到这一点。关于如何在我上面的问题中提到的主要思想,但我不确定这样的实现将如何工作。

4

5 回答 5

7

首先,就目前而言,代码将无法正常工作。的析构函数base至少必须是protected(或派生类是基类的朋友)。析构函数意味着编译器private不允许您为派生类编写析构函数。现在,假设您有一个protected析构函数......(记住,如果您设计一个要扩展的类,请提供公共虚拟析构函数受保护的非虚拟!)

一切都取决于 的实现SmartPointer,特别是std::shared_ptr(或 boost 对应物boost::shared_ptr)能够干净地管理这种情况。该解决方案出于破坏目的执行某种类型的部分类型擦除。基本上,智能指针有一个模板化的构造函数,它接受任何可以分配给指针的base指针,但是因为它是模板化的,所以它知道具体的类型。此时,它存储了一个合成deleter函数,该函数将调用适当的析构函数。

为简单起见,使用std::function

template <typename T>
void delete_deleter( void * p ) {
   delete static_cast<T*>(p);
}

template <typename T>
class shared_pointer {
    T * ptr;
    std::function<void(void*)> deleter;
public:
    template <typename U>
    shared_pointer( U* p, std::function<void()> d = delete_deleter<U> ) 
       : ptr(p), deleter(d)
    {}
    ~shared_pointer() {
       deleter( ptr );  // call the stored destructor
    }
};

该代码仅用于展示,必须针对生产进行调整(在哪里存储function,引用计数...),但这足以让您了解:在对象的确切类型所在的唯一函数中已知(在创建智能指针时),您创建一个包装器,它将调用您需要的析构函数的确切版本(提供一些类型的擦除),然后将其留在周围,当您需要delete对象时调用它而不是运营商delete

这也可以用于管理需要调用特殊方法而不是delete

// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );

同样,在准备好这个生产之前应该做很多工作。

用于简化擦除的依赖关系std::function可以从问题中消除。在简单的情况下(智能指针仅支持分配new和释放的内存),然后只需提供一个具有单个 virtual 的基类,然后使用当前实现将现有的重写从该覆盖重构为模板派生类。如果您需要进行一般情况(持有任何类型的资源),则不值得努力,只需使用or 。deletedeleteroperator()(void*)delete_deleterdeleteroperator()(void*)std::functionboost::function

于 2011-04-26T07:55:33.897 回答
2

首先,你的析构函数不应该是私有的,否则根本不会编译。其次,如果您使用的是“智能指针”,您可能根本不应该手动删除指针(虽然我不知道您使用的是什么实现,但这对我来说很奇怪)。

无论如何,如果您想知道通过指向基类的指针删除对象时如何调用派生类的析构函数,答案是多态性。但是你virtual的析构函数缺少声明,现在你的代码不会调用派生类的析构函数。

大多数 C++ 实现如何实现这一点是通过虚拟表

于 2011-04-26T07:14:42.613 回答
1

如果您使用任何 boost 智能指针或其他不friend属于您的Base类的指针,则此代码将无法编译,因为Base类的析构函数是protected(与private其他独立于Base类的相同)。

现在让我们考虑一下您SmartPointer<Base>Base. 在这种情况下,代码可以工作,但它不会调用 destructor ofDerived而是 destructor of Base,因为这里你的Base类不是多态的。您应该将 destructorotr 声明为Baseas virtual。在最后一种情况下,当您的智能指针被删除时,将调用正确的析构函数。

于 2011-04-26T07:13:01.357 回答
0

该程序无效。

1) base 的 dtor 是私有的

2)base的dtor不是虚的

回答您的问题:您需要更正 #1 和 #2。然后将使用动态调度调用 dtor(它将以相反的构造顺序调用每个 dtor)。

在不进行这些更正的情况下,唯一SmartPointer可以知道在此示例中调用派生的 dtor 的方法,并且以定义的方式,是如果SmartPointer过于聪明(或使用乏味)。

于 2011-04-26T07:14:11.177 回答
0

您的基类析构函数需要是虚拟的,以确保在通过基指针删除时调用派生类的析构函数。

关于虚拟析构函数的维基百科条目

于 2011-04-26T07:15:01.297 回答