我想用std :: make_shared創建一個void指針。由於make_shared應該比shared_ptr(new T)快,並且異常保存,我不知道是否有一個庫函數以make_shared方式創建shared_ptr(new foo)。cpp make_shared for void指針
回答
您可以將任何shared_ptr<foo>
到shared_ptr<void>
沒有與make_shared
相關的效率損失:
#include <memory>
struct foo {};
int main()
{
std::shared_ptr<void> p = std::make_shared<foo>();
}
轉換保持在相同的內存分配foo
與基準計,即使您現在可以通過引用它一個void*
。
更新
這是如何工作的?
一個std::shared_ptr<foo>
的一般結構是兩個指針:
+------> foo
| ^
p1 ---------> (refcount, +) |
p2 --- foo* -----------------------+
p1
指向控制塊含有一個引用計數(實際上是兩個引用計數:一個用於強所有者和一個用於弱所有者),一個刪除器,一個分配器和一個指向對象「動態」類型的指針。 「動態」類型是0構造函數看到的對象的類型,如Y
(可能與T
相同或不同)。
p2
具有類型T*
其中T
相同T
如shared_ptr<T>
。把它看作存儲對象的「靜態」類型。當您取消引用shared_ptr<T>
時,它將被取消引用p2
。在破壞shared_ptr<T>
時,如果引用計數爲零,則它是控制塊中的指針,它有助於銷燬foo
。
在上圖中,控制塊和foo
都是動態分配的。 p1
是擁有指針,並且控制塊中的指針是擁有指針。 p2
是一個非擁有指針。 p2
的只有函數是取消引用(箭頭運算符,get()
等)。
當您使用make_shared<foo>()
,實施有把foo
就在控制塊,引用計數和其他數據的旁邊的機會:
p1 ---------> (refcount, foo)
p2 --- foo* --------------^
這裏的優化是,只有現在有單一分配:現在嵌入foo
的控制塊。
當上述被轉換爲shared_ptr<void>
,發生的是:
p1 ---------> (refcount, foo)
p2 --- void* -------------^
即p2
的類型從foo*
變爲void*
。而已。 (除了增加/減少引用計數以考慮副本和臨時性的破壞 - 可以通過從右值構造來消除)。當引用計數爲零時,它仍然是控制塊,銷燬foo
,通過p1
找到。 p2
不參與銷燬操作。
p1
實際上指向控制塊的通用基類。該基類不知道存儲在派生控制塊中的foo
類型。在實際對象類型Y
已知的時候,導出的控制塊在shared_ptr
的構造函數中構造。但從那時起,shared_ptr
只能通過control_block_base*
與控制塊進行通信。因此,像通過虛擬函數調用發生破壞的事情。
在C++ 11中,來自右值shared_ptr<foo>
的shared_ptr<void>
的「移動構造」只需複製兩個內部指針,而不必操作引用計數。這是因爲右值shared_ptr<foo>
是大概要走開:
// shared_ptr<foo> constructed and destructed within this statement
std::shared_ptr<void> p = std::make_shared<foo>();
這可以最清楚地體現在shared_ptr
構造源代碼:
template<class _Tp>
template<class _Yp>
inline _LIBCPP_INLINE_VISIBILITY
shared_ptr<_Tp>::shared_ptr(shared_ptr<_Yp>&& __r,
typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat>::type)
_NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
__r.__ptr_ = 0;
__r.__cntrl_ = 0;
}
轉換施工前的引用計數只有1 。在轉換結構之後,引用計數仍然是1,並且源在它的析構函數運行之前沒有指向任何東西。簡而言之,這就是移動語義的喜悅! :-)
這是如何工作的?用編譯器優化(討厭依靠那些)?我的理解告訴我,用純粹的C++最好的我可以期望的是移動語義。在閱讀這篇文章後,我會期待一些更復雜的事情。 – ted 2011-12-27 19:46:57
非常詳細的優秀答案!一些開銷(我害怕)似乎留下了(refcount增加,新的共享指針,其中p2的類型爲void,釋放共享指針(指向controlblock的指針,指向對象的指針),其中p2是實際類型)似乎儘管如此。糾正我,如果我錯了。 – ted 2011-12-27 21:51:33
@ted:如果沒有轉換到'shared_ptr
- 1. boost :: bind for void指針參數
- 2. C++ void指針
- 3. C#void指針?
- 4. void指針
- 5. 類的指針void *
- 6. 指針使用CPP
- 7. void *指針上的指針運算
- 8. .cpp的指針和數組
- 9. void函數中的指針
- 10. 對void *指針的常量引用
- 11. int指針變爲void指針,然後變成雙指針
- 12. 如何將void(__thiscall MyClass :: *)(void *)轉換爲void(__cdecl *)(void *)指針
- 13. 右鍵投給void *指針
- 14. 追加兩個void *指針
- 15. 複製到void *指針
- 16. 特殊指針值((void *)1)
- 17. void *與char *指針算術
- 18. 在C++中指向void的指針?
- 19. 使用void指針在C++中打印數組我使用void指針
- 20. 指向字符指針的void-pointer指針
- 21. 綁定void *指向C++/Cli基本類型指針的指針
- 22. 將void指針轉換爲char指針時的麻煩
- 23. 將void指針傳遞給函數指針
- 24. CPP/C++獲取指針值或depointerize指針
- 25. 使用交換函數void指針
- 26. 警告:解除引用'void *'指針
- 27. C:memcpy的段錯誤用void *指針
- 28. 如何在void指針中查找unicode字符指針?
- 29. void指針到升壓的矢量共享指針
- 30. 將void指針的值賦給非空指針
它會創建什麼類型的對象? – 2011-12-27 14:41:53
問題在於,必須有一些不同的語法才能解決這個問題。 make_void_shared(構造函數參數)。我沒有從static_pointer_cast (make_shared (bar1,...,barn)) –
ted
2011-12-27 14:45:38
的性能增益您要求一個shared_ptr來包裝一個void *,然後指向一個真實的對象?但是,這意味着什麼呢? – 2011-12-27 14:47:00