![](/img/trans.png)
[英]boost::shared_ptr<> “explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete”
[英]What is boost's shared_ptr(shared_ptr<Y> const & r, T * p) used for?
boost::shared_ptr
有一個不尋常的構造函數
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
請注意,指針是分開的,但它們都聲稱use_count
為2(因為它們共享同一對象的所有權)。
因此, int
所擁有x
將只要存在x
或 y
是周圍。 如果我理解文檔是正確的,那么第二個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()
那么...是這股一個指針的所有權這個不尋常的結構的實用性,但使用時就像另一個指針(它不擁有)。
當您想要共享一個類成員並且該類的實例已經是shared_ptr時,它非常有用,如下所示:
struct A
{
int *B; // managed inside A
};
shared_ptr<A> a( new A );
shared_ptr<int> b( a, a->B );
他們分享使用數量和東西。 它是內存使用的優化。
為了擴展leiz和piotr的答案, shared_ptr<>
'aliasing'的描述來自WG21論文, “改進C ++ 0x,版本2的shared_ptr
” :
III。 別名支持
高級用戶通常需要能夠創建一個
shared_ptr
實例p
,該實例與另一個(主)shared_ptr
q
共享所有權,但指向不是*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
實例,該實例存儲p
並與r
共享所有權 。后置條件:
get() == p && use_count() == r.use_count()
。拋出:沒什么。
[注意:為了避免懸空指針的可能性,此構造函數的用戶必須確保
p
至少在r
的所有權組被銷毀之前保持有效。 - 結束說明。][注意:此構造函數允許使用非NULL存儲指針創建空的
shared_ptr
實例。 - 結束說明。]
您還可以使用它來保持動態轉換指針,即:
class A {};
class B: public A {};
shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
您可能有指向某個驅動程序或較低級別api的數據結構的指針,該數據結構可能通過其較低級別的api或其他方式分配其他數據。 在這種情況下,增加use_count可能會很有趣,但如果第一個指針擁有其他數據指針則返回附加數據。
我在我的小庫中使用了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!
我不假裝為別名構造函數發明了這個用法,但我從未見過其他人這樣做。 如果你猜測那些臟代碼是否有效,答案是肯定的。
對於“ shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
”
我認為這不是使用智能指針的推薦方式。
推薦的進行此類型轉換的方法應該是:
shared_ptr<B> b(a);
因為在Boost文檔中提到:
只要T *可以隱式轉換為U *,
shared_ptr<T>
就可以隱式轉換為shared_ptr<U>
。 特別是,shared_ptr<T>
可以隱式轉換為shared_ptr<T> const
,也可以轉換為shared_ptr<T> const
shared_ptr<U>
,其中U是T的可訪問基,並且是shared_ptr<void>
。
除此之外,我們還有dynamic_pointer_cast ,它可以直接在Smart Pointer對象上進行轉換,這兩種方法都比手動轉換原始指針方式更安全。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.