shared_ptr的控制块内部的虚函数是什么?

时间:2015-01-31 15:54:19

标签: c++ pointers shared-ptr smart-pointers

我已经阅读过" Item"关于Scott Meyers的 shared_ptr '本书"有效的现代C ++"他说以下内容:

  

通常的控制块实现更多   比你想象的要复杂。它利用了继承,而 甚至还有一个虚函数。 (它用于确保正确销毁指向的对象。)   这意味着使用std :: shared_ptrs也会导致控制块使用的虚函数的机器成本。

然后他并没有解释虚函数究竟是做什么的。据我所知,删除尖头对象的正确方法是使用删除器或类型擦除。所以,请解释一下这是什么。

1 个答案:

答案 0 :(得分:2)

需要虚函数以确保正确删除共享的对象。与unique_ptr不同,shared_ptr在实例化模板时不需要完全了解类型。例如。你可以这样做:

class Foo;
std::shared_ptr<Foo> foo = make_foo();

请注意,在上面的代码中,我们没有完整的Foo类型,只有前向声明。如果我们让foo超出范围,它将指向的对象将被正确删除,因为在Foo中创建了make_foo时,还创建了一个知道完整类型的删除器Foo,因此可以调用适当的析构函数。 (例如,make_foo或许Bar创建一个继承自Foo的{​​{1}}并返回该值。shared_ptr会处理此罚款。)

shared_ptr为管理Foo删除而创建的删除对象上的函数将是虚拟的,允许shared_ptr调用正确的析构函数。

大概这可能是这样的:

struct deleter_interface {
    virtual void ~deleter_interface = default;
    virtual void dispose() = 0;
};

template <typename T>
struct deleter : deleter_interface {
    T* ptr_;
    deleter(T* ptr) : ptr_(ptr) {}
    virtual void dispose() { delete ptr_; }
};

template <typename T>
shared_ptr {
    T* ptr_;
    deleter_interface* deleter_;
    ...
};

template <typename T>
shared_ptr<T>::shared_ptr<T>(T* ptr)
    : ptr_(ptr), deleter_(new deleter<T>(ptr)) {}

template <typename T>
shared_ptr<T>::~shared_ptr<T>() { deleter_->dispose(); delete deleter_; }

虽然这看起来更复杂,但绝对必要,但允许在没有完整类型的情况下使用shared_ptr。例如,如果你想这样做:

在a.h中:

struct Foo;
std::shared_ptr<Foo> a = make_object();
// ... let a go out of scope

在a.cc中:

struct Foo { ... };
struct Bar : Foo { ... };
std::shared_ptr<Foo> make_object() { return std::shared_ptr<Foo>(new Bar); }

如果我们没有删除代码中使用的虚函数,则Bar将无法正确销毁。使用虚函数,标题(a.h)永远不会看到FooBar的定义。