2017-05-28 149 views
15

爲什麼像shared_ptr這樣的類在其構造函數中有另一個模板?通用複製構造函數

例如:

template<class T> class shared_ptr { 
public: 
    template<class Y> 
    explicit shared_ptr(Y * p); 

我一直在讀斯科特邁爾斯的C++有效,項目45表示,它背後的想法是通過他們做出多態性可能;也就是說,從構建shared_ptr<B>shared_ptr<A>如果B從A

衍生而來,但沒有定義諸如

explicit shared_ptr(T * p); 

足夠的構造?我的意思是,這段代碼工作得很好:

class C1 { 
}; 

class C2 : public C1 { 
}; 

template<typename T> 
class A 
{ 
public: 
    A(T &a) 
    { 
    var1 = a; 
    } 

    T var1; 
}; 

int main(int argc, char *argv[]) 
{ 
    C2 c2; 
    A<C1> inst1(c2); 
} 

那麼爲什麼我們需要另一個構造函數模板?

+4

如果這兩種類型不是使用繼承而彼此派生的,但它們彼此之間可以轉換* –

+1

@Someprogrammerdude如果它們可以相互轉換,我的解決方案「無論如何工作?因爲該類將被實例化爲某種類型,並且會發生常規轉換,因爲這是一些T的具體類。 –

+1

即使兩個不同類型的對象可以相互轉換,但類型仍然不同。這意味着模板參數「T」必須表示兩種不同的類型,這是不可能的。 –

回答

13

沒有模板的構造,下面的代碼將有不確定的操作:

#include <memory> 

class Base {}; 
class Derived : public Base {}; 

int main() { 
    std::shared_ptr<Base> ptr(new Derived); 
} 

如果shared_ptr只需Base*,它被強制爲最終調用deleteBase*指針。但由於Base沒有虛擬析構函數,指針實際指向Derived,這是未定義的行爲。

但實際上,上面的代碼格式良好。 shared_ptr的模板構造函數需要一個Derived*指針,並存儲一個自定義的刪除程序,該程序在原始的Derived*指針上調用delete,這很好。

+2

我認爲這是一個很好的解釋,爲什麼它需要'std :: shared_ptr',但我認爲這種模式在標準庫中的其他地方很常見,在這些地方不需要刪除器。 –

+2

這是自定義刪除者的一個相當邊際的副作用。他們是一個很好的額外的東西,而不是shared_ptr背後的動力(這是共享指針)。 –

+0

@n.m .:對一個子對象擁有一個'shared_ptr'並且管理整個對象的生命週期的刪除者的能力是'shared_ptr'的一個非常強大的功能。基礎子對象只是一個特殊情況,其能力還包括成員子對象,甚至包含「擁有的」對象對象。 –

0
explicit shared_ptr(T * p); 

shared_ptr如果只有這個構造函數,它會破壞它的整個目的,是提供一種引用計數指針。

引用計數(或者說是指針)是shared_ptr的一部分。每次創建,銷燬或複製shared_ptr時都應更新它。只有shared_ptr傳遞給複製例程才能實現最後一部分。傳遞一個裸指針將創建一個shared_ptr,引用計數爲1.

引用計數的指針只在引用計數超過1時共享。對於您的計劃,目前尚不清楚這是如何發生的。

一些引用計數功能由普通(非模板)複製構造函數提供。但不是全部。

例如,

std::shared_ptr<Derived> d; 
std_shared_ptr<Base> b; 
... 
b = d; 

會失敗,但不會模板「副本的構造函數進行編譯。我們希望共享poiters提供相同的多態行爲正常的指針,所以我們要在上面建設只是工作。

+1

我想問題是爲什麼我們有'template 顯式shared_ptr(Y *);',而不是爲什麼我們有shared_ptr(const shared_ptr&);和'template shared_ptr(const shared_ptr &);'。 – aschepler

+0

@aschepler我不認爲這個問題完全意識到爲什麼shared_ptr需要一個正常的拷貝構造函數。無論如何,我會添加一些解釋。 –

+0

@ n.m。首先感謝迴應。但是,這些智能指針背後的想法不像具有某些附加功能的普通指針那樣行爲? (例如參考計數)。你寫的代碼,我認爲其中一個應該是'd' –