簡體   English   中英

只與一個所有者建立一個shared_ptr

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM