2009-09-10 116 views
26

boost::shared_ptr有着不同尋常的構造什麼是boost的shared_ptr(shared_ptr <Y> const&r,T * p)用於?

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

,我以什麼這將是有益的有點摸不着頭腦。基本上它與r共享所有權,但.get()將返回p不是r.get()

這意味着你可以做這樣的事情:

int main() { 
    boost::shared_ptr<int> x(new int); 
    boost::shared_ptr<int> y(x, new int); 

    std::cout << x.get() << std::endl; 
    std::cout << y.get() << std::endl; 

    std::cout << x.use_count() << std::endl; 
    std::cout << y.use_count() << std::endl; 
} 

,你會得到這樣的:

0x8c66008 
0x8c66030 
2 
2 

注意,指針是分開的,但他們都聲稱有2的use_count (因爲他們共享同一個對象的所有權)。

所以,通過x擁有的int會存在,只要xy周圍。如果我理解文檔正確,第二個int永遠不會被破壞。我用下面的測試程序證實了這一點:

struct T { 
    T() { std::cout << "T()" << std::endl; } 
    ~T() { std::cout << "~T()" << std::endl; } 
}; 

int main() { 
    boost::shared_ptr<T> x(new T); 
    boost::shared_ptr<T> y(x, new T); 

    std::cout << x.get() << std::endl; 
    std::cout << y.get() << std::endl; 

    std::cout << x.use_count() << std::endl; 
    std::cout << y.use_count() << std::endl; 
} 

該輸出(如預期):

T() 
T() 
0x96c2008 
0x96c2030 
2 
2 
~T() 

所以......這是什麼不尋常的結構的這股一個指針的所有權的有效性,但行爲像使用時的另一個指針(它不擁有)。

+7

好問題。 +1 – GManNickG 2009-09-10 05:43:59

+3

TL; DR版本:它創建一個指向「r」子對象的指針。 – 2013-07-13 16:15:41

回答

29

當你想與大家分享類成員和類的一個實例,它是有用的已經是一個shared_ptr的,像下面這樣:

struct A 
{ 
    int *B; // managed inside A 
}; 

shared_ptr<A> a(new A); 
shared_ptr<int> b(a, a->B); 

他們分享使用次數和東西。這是內存使用的優化。

+1

一個很好的答案。顯然,在這個例子中,只要'b'在附近,我們就想保留'a'的對象。我認爲我們有一個勝利者。 – 2009-09-10 18:54:19

+0

不僅對內存使用進行了優化,而且在具體的例子中,使用不同的方法最終會調用'delete(a-> B)',這可能是意想不到的(考慮struct A {int b;}; shared_ptr a(new A); shared_ptr b(a,&a-> b)') – 2010-03-16 13:48:12

2

您可能有一個指向某個驅動程序或較低級別api的數據結構的指針,該結構可能會通過其較低級別的API或其他方式分配其他數據。在這種情況下,增加use_count可能會很有趣,但如果第一個指針擁有其他數據指針,則返回附加數據。

8

爲了擴展leiz'spiotr's答案,shared_ptr<> '混疊' 的描述是從WG21紙,"Improving shared_ptr for C++0x, Revision 2"

III。走樣支持

高級用戶往往需要創建一個shared_ptr 實例p共享與 另一個(主)shared_ptrq但 點所有權的對象不是一個基地*q 的 能力。例如,*p可以是*q的成員或 元素。這 部分提出了一個額外的 構造函數,可用於此 的目的。

的這個 增加表現力的一個有趣的副作用是 現在*_pointer_cast功能可以在 用戶代碼來實現。工廠功能 make_shared工廠功能 本文檔後面也可以是 實施只使用公共 接口的shared_ptr通過 通過別名構造函數。

影響:

此功能擴展的 shared_ptr在增加其表達 功率,並因此強烈 建議要添加到的C++ 0x 標準向後兼容 方式的界面。它沒有介紹源代碼和 二進制兼容性問題。

建議文本:

加入shared_ptr [util.smartptr.shared]以下 構造:

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

添加以下 [util.smartptr。 shared.const]:

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

影響:構造一個shared_ptr實例存儲與rp股份所有權。

後續條件:get() == p && use_count() == r.use_count()

引發:什麼也沒有。

[注:爲了避免懸空指針的可能性,此構造的用戶 必須確保p仍然有效,至少 直到r所有權組被銷燬。 - 注完]

[注:此構造允許shared_ptr 實例的創建與非NULL指針存儲。 - 注完]

4

您也可以使用這種方式來保持動態鑄造指針,即:

class A {}; 
class B: public A {}; 

shared_ptr<A> a(new B); 
shared_ptr<B> b(a, dynamic_cast<B*>(a.get())); 
+0

另一個有趣的用途,顯然屬於「別名」的範疇。好點子。 – 2010-08-11 14:36:40

0

爲 「shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

我認爲這是不使用智能指針的推薦方式。

做這種類型的轉換的推薦的方法應是:

shared_ptr<B> b(a); 

由於升壓文獻中,提到的是:

shared_ptr<T>可以隱 轉換爲shared_ptr<U>每當T * 可以被隱式轉換爲U *。在 特別地,shared_ptr<T>是 隱式轉換爲shared_ptr<T> const, 到shared_ptr<U>其中U是T的 訪問的基礎上,並 shared_ptr<void>

除此之外,我們也有dynamic_pointer_cast 這可能直接做智能指針對象無一不這兩種方法的轉換會比手工鑄造的原料指針方式更安全。

0

我已經把shared_ptr的的混疊構造函數中使用我的小庫:

http://code.google.com/p/infectorpp/(只是我簡單的IoC容器)

的一點是,因爲我需要已知類型的一個shared_ptr從一個返回多態類(不知道類型)。我無法隱式地將shared_ptr轉換爲我需要的類型。

在文件「InfectorHelpers.hpp」(第72-99行)中,您可以看到IAnyShared類型的操作。

混疊構造函數創建的shared_ptr不刪除他們實際上是指向指針,但他們仍然增加引用計數器原來的對象,並且可以大大有用。

基本上你可以使用別名構造函數創建一個指向任何東西的指針並威脅它作爲引用計數器。

//my class 
std::shared_ptr<T> ist; 
int a; //dummy variable. I need its adress 

virtual std::shared_ptr<int> getReferenceCounter(){ 
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing 
} 

virtual void* getPtr(); //return raw pointer to T 

現在我們有兩個「的引用計數器」的指針和指向T的istance,足夠的數據來創建一些與混疊構造

std::shared_ptr<T> aPtr(any->getReferenceCounter(), //share same ref counter 
       static_cast<T*>(any->getPtr())); //potentially unsafe cast! 

我不想假裝已經發明瞭這個用於別名構造函數,但我從來沒有見過其他人在做同樣的事情。如果你猜測這個髒代碼是否有效,答案是肯定的。

相關問題