具有相同原始指针的 shared_ptr<Base> 和 shared_ptr<Derived> 的实例会共享引用计数吗?
Will instance of shared_ptr<Base> and shared_ptr<Derived> with same raw pointer share reference count?
假设我有两个 类、Base
和 Derived
,其中 Derived
继承自 Base
。现在,假设我执行以下代码:
shared_ptr<Derived> derivedPtr = make_shared<Derived>();
shared_ptr<Base> basePtr = derivedPtr;
将 derivedPtr
复制到 basePtr
是否会导致更新 derivedPtr
的引用计数(以便 derivedPtr.use_count()
和 basePtr.use_count()
等于 2) ?或者,由于 shared_ptr
的两个实例是不同的类型,这两个实例是否具有不共享的单独引用计数(因此 derivedPtr.use_count()
和 basePtr.use_count()
等于 1)?
所以shared_ptr
不仅仅是一个指针和一个引用计数。
它是一个指针,也是一个指向控制块的指针。该控制块包含强计数、弱计数和销毁函数。
shared_ptr
.
有3种构造方法
首先,您可以从原始指针构造它。当发生这种情况时,它会分配一个控制块并将一个 "destroyer" 函数插入其中以销毁原始指针内存 (delete t;
)。
其次,可以使用make_shared
。这为控制块和其中的对象分配了一个 space 的块。然后它将销毁器设置为只销毁对象,而不回收内存。控制块的析构函数清除了两个内存分配。
第三,别名构造函数。这些 共享 控制块(以及因此破坏代码),但具有不同的对象指针。
最常见的别名构造函数是创建指向基的指针的构造函数,您在上面就是这样做的。指向基的指针不同于您创建它的共享指针,但控制块保持不变。因此,每当控制块达到 0 强引用计数时,它就会将对象作为其原始派生对象销毁。
比较少见的可以用来return指向成员变量的共享指针,像这样:
struct Bob {
int x;
};
auto pBob = std::make_shared<Bob>();
pBob->x = 7;
auto pInt = std::shared_ptr<int>( pBob, &(pBob->x) );
现在 pInt
是指向 pBob->x
的指针,它共享上面 2 行创建的 Bob
的引用计数(我们创建 pBob
的地方)。
pBob = {};
现在指向 Bob
的最后一个指针消失了,但对象仍然存在,由 pInt
的控制块(和强计数)所有权保持活动状态。
然后当我们:
pInt = {};
最后 Bob
被释放。
您在问题中所做的强制转换为基数的隐式转换只是其变体。
第二个别名构造函数也可以用来做非常奇怪的事情,但那是另一个话题了。
shared/weak ptr 是其中一种情况,您似乎可以 "monkey code" 它而不理解它,但根据我使用共享所有权的经验,完全理解共享 ptr 是(a ) 比获得共享所有权更容易,并且 (b) 使获得共享所有权更容易。
假设我有两个 类、Base
和 Derived
,其中 Derived
继承自 Base
。现在,假设我执行以下代码:
shared_ptr<Derived> derivedPtr = make_shared<Derived>();
shared_ptr<Base> basePtr = derivedPtr;
将 derivedPtr
复制到 basePtr
是否会导致更新 derivedPtr
的引用计数(以便 derivedPtr.use_count()
和 basePtr.use_count()
等于 2) ?或者,由于 shared_ptr
的两个实例是不同的类型,这两个实例是否具有不共享的单独引用计数(因此 derivedPtr.use_count()
和 basePtr.use_count()
等于 1)?
所以shared_ptr
不仅仅是一个指针和一个引用计数。
它是一个指针,也是一个指向控制块的指针。该控制块包含强计数、弱计数和销毁函数。
shared_ptr
.
首先,您可以从原始指针构造它。当发生这种情况时,它会分配一个控制块并将一个 "destroyer" 函数插入其中以销毁原始指针内存 (delete t;
)。
其次,可以使用make_shared
。这为控制块和其中的对象分配了一个 space 的块。然后它将销毁器设置为只销毁对象,而不回收内存。控制块的析构函数清除了两个内存分配。
第三,别名构造函数。这些 共享 控制块(以及因此破坏代码),但具有不同的对象指针。
最常见的别名构造函数是创建指向基的指针的构造函数,您在上面就是这样做的。指向基的指针不同于您创建它的共享指针,但控制块保持不变。因此,每当控制块达到 0 强引用计数时,它就会将对象作为其原始派生对象销毁。
比较少见的可以用来return指向成员变量的共享指针,像这样:
struct Bob {
int x;
};
auto pBob = std::make_shared<Bob>();
pBob->x = 7;
auto pInt = std::shared_ptr<int>( pBob, &(pBob->x) );
现在 pInt
是指向 pBob->x
的指针,它共享上面 2 行创建的 Bob
的引用计数(我们创建 pBob
的地方)。
pBob = {};
现在指向 Bob
的最后一个指针消失了,但对象仍然存在,由 pInt
的控制块(和强计数)所有权保持活动状态。
然后当我们:
pInt = {};
最后 Bob
被释放。
您在问题中所做的强制转换为基数的隐式转换只是其变体。
第二个别名构造函数也可以用来做非常奇怪的事情,但那是另一个话题了。
shared/weak ptr 是其中一种情况,您似乎可以 "monkey code" 它而不理解它,但根据我使用共享所有权的经验,完全理解共享 ptr 是(a ) 比获得共享所有权更容易,并且 (b) 使获得共享所有权更容易。