2012-09-09 108 views
1

我對shared_ptr拷貝構造函數有些疑惑。請考慮以下2行:shared_ptr的拷貝構造函數裏面

  1. 這是一個「常數」引用一個shared_ptr對象,傳遞給拷貝構造函數,以便其他shared_ptr的對象初始化。

  2. 複製構造函數應該還會增加一個成員數據 - 「引用計數器」 - 它也在所有shared_ptr對象之間共享,因爲它是一個引用/指向某個整數的指針,告訴每個shared_ptr對象如何他們中的許多人還活着。

但是,如果拷貝構造函數試圖遞增引用計數構件的數據,它不是「打」按引用傳遞shared_ptr的的常量性?或者,拷貝構造函數是否在內部使用const_cast操作符來臨時刪除參數的常量?

回答

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 * constf,但它是不是一個int const * const!換句話說,你不能改變x.p,但你可以改變*x.p

這實際上是在共享指針複製構造函數中發生了什麼(其中*p扮演引用計數器的角色)。

2

它使用一個內部指針不繼承該參數的比賽,如:

(*const_ref.member)++; 

是有效的。

0

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

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,操縱引用計數也不是問題(並且不需要const_castmutable)。

我應該補充一點,實際上,您可能會將代碼結構與此不同 - 特別是,您通常會將更多(所有?)代碼操作引用計數到shared_ptr_internal (或任何你決定稱之爲)本身,而不是與父母shared_ptr類中的那些人混淆。

您通常還會支持weak_ptr s。爲此,對於指向同一個shared_ptr_internal對象的weak_ptr s的數量,您有第二個引用計數。你破壞了最終的指針對象物體時shared_ptr引用計數爲0,但只破壞shared_ptr_internal對象當兩個shared_ptrweak_ptr引用計數變爲0

0

哇,真是大開眼界這已經全部!感謝大家,我已經能夠將混淆的原因歸結爲我始終認爲以下事實(「a」包含「b」的地址)的事實都是等同的。

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

但我錯了!只有前兩個選項是相同的。第三個完全不同。

使用option1或option2,「a」可以指向任何它想要的內容,但不能更改它指向的內容。

隨着option3,一旦決定「a」指向什麼,它就不能指向其他任何東西。但是它可以自由地改變它指向的內容。所以,shared_ptr使用option3是有道理的。