[英]Make a shared_ptr with only one owner
我在C ++ 11中有一個只有一個所有者的對象。 但是,其他對象可以將weak_ptr
保存到此對象。 這樣,我可以在使用之前測試對象是否仍然存在。
目前,所有者擁有該對象的shared_ptr
,該對象的所有者總數為1。
如何確保不允許任何人制作此shared_ptr
的副本?
我不能使用unique_ptr
因為顯然C ++ 11不允許從unique_ptr
創建weak_ptr
。
編輯 :謝謝你的回復!
所有程序都在一個線程上運行。 主要擁有一個定期更新循環,在其中調用其所有子系統。
感謝您指出使用weak_ptr
實際上創建了一個shared_ptr
。 期望在調用另一個非const函數期間不允許子系統或對象存儲shared_ptr
。 這樣,任何函數都可以要求所有者從其集合中刪除對象,並立即刪除該對象。
我希望每次子系統調用lock()
時都要避免增加shared_ptr
引用計數的開銷,因為它應該立即釋放所有權(並確保在編譯時就是這種情況)。
編輯2 :更清楚地表達我的問題的示例代碼
class Manager {
public:
Manager(); //Creates objects and stuff
void updateAllObjects() {
for (auto& o : mObjects)
o->update(*this);
}
void deleteObject(weak_ptr<WorldObject>); //May be called by other objects
vector<shared_ptr<WorldObject>> mObjects;
};
class WorldObject {
public:
virtual void update(Manager&)=0;
};
class Passenger : public WorldObject {
public:
void update(Manager&);
};
class Car : public WorldObject {
public:
void update(Manager&); //May call Manager::deleteObject on its passengers, or change them etc...
//If Manager decides to delete passenger, they must be destroyed, so we don't want those references to count
vector<weak_ptr<Passenger>> mPassengers;
//A passenger can belong to several cars, and must be updated exactly once per WorldObject::update()
};
如何: - 避免存儲許多shared_ptr
的開銷 - 確保Car
不會將shared_ptr
存儲給乘客的時間超過其Car::update()
函數
目前,所有者擁有該對象的shared_ptr,該對象的所有者總數為1。
這是一個錯誤的聲明,因為std::weak_ptr
所有者只能通過創建std::shared_ptr
來使用它,所以所有者數量將> 1.所以你的問題幾乎毫無意義 - 如果你想只提供獨占訪問權限對象移動std::unique_ptr
,如果你想通過std::weak_ptr
使用它,它必須是共享的,原則上你不能強制執行單個所有者。
你不能, shared_ptr
的本質是你可以創建更多的實例。 你可以做的是使它成為類的私有成員,並且不要像現在那樣直接將shared_ptr
公開給外部世界。 但是你無法安全地使用啞巴,有人可以獲得一個weak_ptr
,提取原始指針並刪除它。 如果yoru級的用戶想要用腳射擊自己,那么你無能為力!
如果不實現自己的valid_ptr
或類似的東西,就不能這樣做,因為你總是可以通過weak_ptr :: lock獲得另一個shared_ptr。 也就是說,只有當你想要定期檢查對象是否被刪除時(即不檢查對象是否仍然存在或實際訪問它,請參閱下文!)
template<typename T>
class valid_ptr {
public:
template<typename S>
valid_ptr(const std::weak_ptr<S>& r) : m_ptr(r) { }
bool expired() const { return m_ptr.expired(); }
private:
std::weak_ptr<T> m_ptr;
};
如果你真的想要訪問你的指針,那么你應該簡單地使用weak_ptr它的意圖,並通過weak_ptr::lock
獲取訪問持續時間的shared_ptr:
if (auto shared = weak.lock()) {
// ptr is valid and can now be used via the shared_ptr shared
} else {
// ptr is nullptr
}
你不應該只是依靠一個積極的expired
檢查來訪問該對象,因為在檢查和訪問之間可能發生任何事情(包括被刪除的對象,除非你有一些額外的約束,你沒有在你的問題中提到)。 在這種情況下,您希望通過在訪問期間獲取shared_ptr來確保(共享)所有權。
不要這樣做。
如果你必須:
將共享ptr用於包含可寫的唯一ptr包裝的互斥鎖定仿函數。
其他人獲取共享ptr到一個互斥包裝函數包裝一個可能為null的不可變原始ptr,通過包裝上面的方法並在apply
公開.get()
結果來實現。
所有者仿函數由一位代碼擁有。 它暴露了非所有者的仿函數。 它可以摧毀獨特的ptr。
非所有者仿函數不能延長對象的生命周期超過其互斥鎖。
所有者仿函數可以將唯一的ptr設置為空,並且(一旦它們具有互斥鎖),沒有人可以阻止它們。
您可以使用共享互斥鎖來允許多個讀者。
仿函數是什么意思?
仿函數是包含另一種支持apply的類型的類型。 如果[T]
是仿函數類型,並且T
是包裝類型,並且T->U
是取T
並返回U
的函數的類型,則apply操作的類型為:
([T],(T->U))->U
要么
[T].apply(T->U)
返回一個U
如果T
是一個類型,則將T->U
應用於T
以獲得U
如果[T]
是一個仿函數T
,那么你將它應用於T->U
獲得U
。 (注意與前一段相比,措辭略有變化)。
T
的函子知道如何運行T
函數,但沒有聲稱是 T
實施明智,它要么包含一個T
要么知道如何在被問到時獲得一個。 它可以使它是如何運行的功能的其他擔保(例如,具有互斥鎖保護,在一個專門的線程,在服務器上,等等)。
有關詳細信息,請參閱Haskell。
另請注意,使用合理的公理不能支持重入,因此可以在單個線程上進行死鎖。
這個答案不容易理解:我只是為了完整而包含它。 除非你從現代函數編程背景來到C ++,否則任何提出OP問題的人都可能不會得到這個,也不應該嘗試(我只是試圖表明OP的請求是可能的 ,nkt這是個好主意) 。 更糟糕的是,如果不是設計,我可能會得到一些函數式編程術語錯誤。
如何將std :: unique_ptr用於對象而不是std :: weak_ptr這是一個指向此std :: unique_ptr的原始指針。 這樣,對象只有一個所有者,您可以使用bool運算符通過指向它的原始指針測試std :: unique_ptr的有效性。
auto object = std::make_unique<T>(...); // creates object and std::unique_ptr
...
auto* object_user = &object; // raw pointer to the std::unique_ptr holding the object
...
if ( *object_user ) (*object_user)->... // using the object
注意:省略號是您需要的任何代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.