2

我对 shared_ptr 复制构造函数有些困惑。请考虑以下两行:

  1. 它是对 shared_ptr 对象的“常量”引用,它被传递给复制构造函数,以便初始化另一个 shared_ptr 对象。

  2. 复制构造函数还应该增加一个成员数据 - “引用计数器” - 它也在所有 shared_ptr 对象之间共享,因为它是一个指向某个整数的引用/指针,告诉每个 shared_ptr 对象其中有多少仍然存在活。

但是,如果复制构造函数试图增加引用计数成员数据,它不会“击中”通过引用传递的 shared_ptr 的常量吗?或者,复制构造函数是否在内部使用 const_cast 运算符来临时删除参数的 const 性?

4

5 回答 5

5

您遇到的现象对于共享指针来说并不特殊。这是一个典型的原始示例:

struct Foo
{
    int * p;
    Foo() : p(new int(1)) { }
};

void f(Foo const & x)  // <-- const...?!?
{
    *x.p = 12;         // ...but this is fine!
}

里面确实有x.p类型,但不是!换句话说,你不能改变,但你可以改变。int * constfint const * constx.p*x.p

这本质上是共享指针复制构造函数中发生的事情(其中*p扮演引用计数器的角色)。

于 2012-09-09T20:11:25.900 回答
3

尽管其他答案是正确的,但它们的应用方式可能不会立即显现出来。我们所拥有的是这样的:

template <class T>
struct shared_ptr_internal {
    T *data;
    size_t refs;
};

template <class T>
class shared_ptr {
    shared_ptr_internal<T> *ptr;
public:
    shared_ptr(shared_ptr const &p) { 
        ptr = p->ptr;
        ++(ptr->refs);
    }
    // ...
};

这里重要的一点是 shared_ptr 只包含一个指向包含引用计数的结构的指针。事实上,它shared_ptr本身const并不影响它指向的对象(我称之为shared_ptr_internal)。因此,即使/如果shared_ptr本身是const,操作引用计数也不是问题(并且不需要 aconst_castmutable两者之一)。

我可能应该补充一点,实际上,您的代码结构可能与此有所不同——特别是,您通常会将更多(全部?)代码用于操作引用计数到 shared_ptr_internal (或任何您决定调用它)本身,而不是与父shared_ptr类中的那些混淆。

您通常还会支持weak_ptrs. 为此,您需要对weak_ptr指向同一shared_ptr_internal对象的 s 数量进行第二个引用计数。当shared_ptr引用计数变为 0 时销毁最终的指针对象,但仅当引用计数shared_ptr_internal引用计数都变为 0 时才销毁该对象。shared_ptr weak_ptr

于 2012-09-10T00:51:47.013 回答
2

它使用不继承参数竞争的内部指针,例如:

(*const_ref.member)++;

已验证。

于 2012-09-09T19:40:40.213 回答
0

指针是常量,但不是指向的值。

于 2012-09-09T20:13:26.120 回答
0

哇,这真是令人大开眼界!感谢大家,我能够确定混淆的根源,因为我总是假设以下内容(“a”包含“b”的地址)都是等价的。

int const  *a = &b;    // option1
const int  *a = &b;    // option2
int * const a = &b;    // option3

但是我错了!只有前两个选项是等效的。第三个完全不同。

使用 option1 或 option2,“a”可以指向它想要的任何东西,但不能更改它所指向的内容。

使用选项 3,一旦确定“a”指向什么,它就不能指向其他任何东西。但是可以自由更改它所指向的内容。因此,shared_ptr 使用 option3 是有道理的。

于 2012-09-10T11:30:56.273 回答