我想用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. void指針
- 2. C++ void指針
- 3. 類的指針void *
- 4. 指針使用CPP
- 5. 對void *指針的常量引用
- 6. 如何將void(__thiscall MyClass :: *)(void *)轉換爲void(__cdecl *)(void *)指針
- 7. 特殊指針值((void *)1)
- 8. void *與char *指針算術
- 9. 右鍵投給void *指針
- 10. 追加兩個void *指針
- 11. 在C++中指向void的指針?
- 12. 綁定void *指向C++/Cli基本類型指針的指針
- 13. 將void指針傳遞給函數指針
- 14. 警告:解除引用'void *'指針
- 15. C:memcpy的段錯誤用void *指針
- 16. 如何在void指針中查找unicode字符指針?
- 17. 結構成員中的void指針和函數指針
- 18. CPP參考性病的指針::列表
- 19. C void *函數指針參數
- 20. 返回void的C++/C函數指針*
- 21. 在void *指針中引用問題?
- 22. void指針函數的輸出
- 23. 鑄造指針對象爲void *在C++
- 24. 試驗在C++ void指針刪除
- 25. 將void指針傳遞給LLVM IRBuilder CreateCall
- 26. 鑄造void指針,以結構
- 27. 在C++中刪除void *指針
- 28. 什麼是C++中的void指針?
- 29. C:從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