shared_ptr 的控制块中的虚函数是什么?
What is the virtual function inside of shared_ptr's Control Block?
我在 Scott Meyers 的书中 "Effective Modern C++" 读过关于 shared_ptr 的 "Item",他说了以下内容:
The usual control block implementation is more
sophisticated than you might expect. It makes use of inheritance, and there’s even a virtual function. (It’s used to ensure that the pointed-to object is properly destroyed.)
That means that using std::shared_ptrs also incurs the cost of the machinery for the virtual function used by the control block.
然后他没有解释虚函数的具体作用。据我所知,删除指向对象的正确方法是使用删除器或类型擦除。所以,请解释一下这是关于什么的。
需要虚拟函数以确保正确删除正在共享的 object。与 unique_ptr
不同,shared_ptr
在实例化其模板时不需要完全了解类型。例如。你可以这样做:
class Foo;
std::shared_ptr<Foo> foo = make_foo();
请注意,在上面的代码中,我们没有完整的 Foo 类型,只有前向声明。如果我们让 foo
超出范围,它指向的 object 将被正确删除,因为当 Foo
在 make_foo
中创建时,也会创建一个删除器,它知道Foo
的完整类型,因此可以调用适当的析构函数。 (例如,也许 make_foo
创建了一个继承自 Foo
和 returns 的 Bar
。shared_ptr
可以很好地处理这个问题。)
shared_ptr
创建的用于管理 Foo
删除的删除器 object 上的函数将是虚拟的,允许 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
就不会被正确析构。使用虚函数,header (a.h) 永远不会看到 Foo
或 Bar
.
的定义并不重要
我在 Scott Meyers 的书中 "Effective Modern C++" 读过关于 shared_ptr 的 "Item",他说了以下内容:
The usual control block implementation is more sophisticated than you might expect. It makes use of inheritance, and there’s even a virtual function. (It’s used to ensure that the pointed-to object is properly destroyed.) That means that using std::shared_ptrs also incurs the cost of the machinery for the virtual function used by the control block.
然后他没有解释虚函数的具体作用。据我所知,删除指向对象的正确方法是使用删除器或类型擦除。所以,请解释一下这是关于什么的。
需要虚拟函数以确保正确删除正在共享的 object。与 unique_ptr
不同,shared_ptr
在实例化其模板时不需要完全了解类型。例如。你可以这样做:
class Foo;
std::shared_ptr<Foo> foo = make_foo();
请注意,在上面的代码中,我们没有完整的 Foo 类型,只有前向声明。如果我们让 foo
超出范围,它指向的 object 将被正确删除,因为当 Foo
在 make_foo
中创建时,也会创建一个删除器,它知道Foo
的完整类型,因此可以调用适当的析构函数。 (例如,也许 make_foo
创建了一个继承自 Foo
和 returns 的 Bar
。shared_ptr
可以很好地处理这个问题。)
shared_ptr
创建的用于管理 Foo
删除的删除器 object 上的函数将是虚拟的,允许 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
就不会被正确析构。使用虚函数,header (a.h) 永远不会看到 Foo
或 Bar
.