C++11引用计数智能指针设计

C++11 Reference count smart pointer design

我正在读这个,
http://www.informit.com/articles/article.aspx?p=31529&seqNum=5
和作者讲解了三种类型的智能指针设计(见文末图片post)。

我相信当前的 GCC、CLang 和可能的 Visual C++ 使用 smart pointers with control block

我可以想象为什么不使用 intrusive reference counting,但是第二个实现的问题是什么 - smart pointer with pointer to pointer block?应该有两个指针取消引用,但智能指针对象大小将只有一半。

带控制块的智能指针

带有指针块指针的智能指针

具有侵入式引用计数的智能指针

一个重要的原因是性能,如果对象地址直接存储在 shared_ptr 对象中,shared_ptr::get() 不必取消引用指针来查找对象地址。

但是除了性能之外,smart pointer with pointer to pointer block 实现不支持您可以使用 shared_ptr 做的所有事情,例如

std::shared_ptr<int> pi(new int(0));
std::shared_ptr<void> pv = pi;
std::shared_ptr<int> pi2 = static_pointer_cast<int>(pv);

struct A {
  int i;
};
std::shared_ptr<A> pa(new A);
std::shared_ptr<int> pai(pa, pa->i);

struct B { virtual ~B() = default; };
struct C : B { };
std::shared_ptr<B> pb(new C);
std::shared_ptr<C> pc = std::dynamic_pointer_cast<C>(pb);

在这些示例中 pvpaipb 存储的指针与控制块拥有的指针类型不同,因此必须有第二个指针(可能是不同的类型)存储在 shared_ptr 本身。

对于pvpb,可以通过将存储在控制块中的指针转换为需要返回的类型来使其工作。这在某些情况下会起作用,尽管有一些使用多重继承的示例无法正常工作。

但是对于 pai 示例(它使用别名构造函数),如果不在控制块中存储一个与指针分开的指针,就无法实现它,因为这两个指针是完全不相关的类型而且你不能在它们之间转换。

您在评论中说:

I see and in case of make_shared, second pointer points to the address internal to the allocated block. (I actually tried this already and it seems that way)

是的,没错。还有第二个指针,但是两个指针指向同一个内存块。这样做的好处是只需要一个内存分配,而不是为对象和控制块分配两个单独的内存。此外,对象和控制块在内存中相邻,因此更有可能共享缓存行。如果 CPU 已经在其缓存中获得了引用计数,那么它的缓存中可能也有该对象,因此访问它们会更快,并且意味着有另一个缓存行可用于其他数据。