shared_ptr控制块内部的虚拟功能是什么?



我在斯科特·迈耶斯(Scott Meyers)的《有效的现代C++》(Effective Modern )一书中读到过一个关于shared_ptr的"项目",他说:

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

然后他没有解释虚函数到底做了什么。据我所知,删除指向对象的正确方法是使用删除器或类型擦除。所以,请解释一下这是关于什么的。

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

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

请注意,在上面的代码中,我们没有完整的 Foo 类型,只有前向声明。如果我们让foo超出范围,它指向的对象将被正确删除,因为当Foomake_foo中创建时,还创建了一个删除器,它知道Foo的完整类型,因此可以调用适当的析构函数。(例如,也许make_foo创建一个从Foo继承并返回的Barshared_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的定义并不重要。

相关内容

  • 没有找到相关文章

最新更新