簡體   English   中英

在這種情況下,應該使用unique_ptr還是shared_ptr?

[英]Should I use unique_ptr or shared_ptr in this case?

在我的QT應用程序的主窗口中,我使用std::shared_ptr來保存指向網絡服務實例的指針,該實例管理與多個客戶端的所有連接。 現在,我必須將此指針傳遞給多個子窗口,以便它們可以與客戶端進行通信。

我最好在主窗口和子窗口中使用std::shared_ptr成員變量,並在創建子窗口時通過復制它,還是更好地使用std::unique_ptr並將原始指針傳遞給子Windows,如主窗口仍然會超過子窗口?

非常感謝!

主要的實際區別是當子窗口仍然存在並且正在使用網絡服務時,主窗口被破壞時會發生什么:

  • 如果您使用unique_ptr並傳遞原始指針,那么您將獲得未定義的行為。
  • 如果您使用shared_ptr則網絡服務將保留到所有子窗口都被銷毀為止。

現在,如果這種條件在設計上是不可能的,那么不確定的行為本質上就不是問題。 如果這種情況由於錯誤而仍然發生,那么如果網絡服務與主窗口一起被破壞,則可能會幫助您檢測到該錯誤,如果您使用unique_ptr ,則會發生這種情況。 使用unique_ptr表示主窗口是唯一擁有網絡服務的東西,其他人僅按照主窗口的指示使用它。

另一方面,如果您以后更改設計並希望使條件合法,或者如果您想以不同的方式使用子窗口,則意味着它們都不會使用一個單獨的網絡服務對象,並且所有對象都不會使用,那么如果您從一開始就使用了shared_ptr ,它將更加容易。 使用shared_ptr表示所有窗口都共享網絡服務的所有權。

我認為一般來說,是否應該在面對“不可能的條件”時嘗試使代碼繼續工作是不可能的。 在這種情況下,這樣做非常便宜(當然, shared_ptr復制比原始指針要昂貴,但是與創建子窗口相比,復制要便宜,並且代碼的結構相同)。 靈活地使“不可能的條件”在某些情況下發生是很有用的,例如在對子窗口代碼進行單元測試時。 因此,可以使用shared_ptr來提高靈活性。 如果由於其他原因而強制執行生存期約束很重要,那么您可能不希望有任何靈活性,在這種情況下,請避免編寫只會隱藏錯誤的代碼。

實際上,您還沒有探索過第三種選擇。

  • 傳遞shared_ptr可以讓您擁有多個所有者,但是在您看來,這是不必要的
  • 使用unique_ptr並傳遞原始指針將強制執行一個所有者,但是如果發生錯誤,則您將面臨不確定的行為(崩潰)。

第三種選擇是使用weak_ptr結合兩種方法:

  • 主窗口在shared_ptr 擁有設備
  • 子窗口傳遞了一個weak_ptr

當子窗口需要使用設備進行通信時,它們將在weak_ptr上使用lock()臨時獲取shared_ptr 然后,您可以斷言拋出 shared_ptr是否為空(這是一個錯誤),否則可以使用它與設備進行通信,然后在完成時將其釋放。


編輯 :正如史蒂夫·傑索普(Steve Jessop)指出的那樣,另一個斷言是有用的(並且可以實現):確保在主窗口銷毀shared_ptr它是最后的所有者,並且設備被釋放(以防止所有權意外泄漏)。

不幸的是,幼稚的方式斷言它在銷毀之前是unique ,因而遭受了種族條件的折磨。 在調用unique銷毀和實際銷毀之間,調用weak_ptr::lock可以創建一個新所有者。

可以簡單地完成,但是:

  1. 從您的shared_ptr創建一個名為monitor的新的weak_ptr
  2. 重置shared_ptr
  3. 調用monitor.lock() ,如果它返回一個非null的shared_ptr則說明存在一個所有者。

有關使用std::shared_ptrstd::unique_ptr的問題主要是所有權之一。 一次只能有一個所有者嗎? 還是該對象有多個所有者?

在您的情況下,您似乎想要多個所有者,因此采用std::shared_ptrstd::shared_ptr的方法。

不要使用std::unique_ptr然后傳遞原始包裝的指針。 當您忘記它並且std::unique_ptr對象超出范圍,而其他人仍然可以訪問原始指針時,它將再次咬住您。

在我看來,網絡服務是在您的程序生命期內應存在的對象。 在這種情況下,不能確定應使用任何類型的智能指針。 最明顯的解決方案是main的局部變量。 無論如何,首先要問自己的是對象的壽命應該是多少。 如果該生存期與main的范圍(或任何其他函數的范圍)相對應,則應采用局部變量。 如果該生存期應與主窗口的生存期相對應,則主窗口的成員變量將是適當的解決方案。 這完全取決於您的應用程序如何指定對象生存期(這是一個設計問題,無法通過低級編程技術解決)。

關於唯一的情況,您可能需要使用指針,如果類型是多態的,並且直到運行時才知道實際類型(例如,因為它是由配置文件中的條目確定的)。 在這種情況下,您必須自己管理生命周期,但是如果確實與作用域相對應,則std::unique_ptr可能是一個很好的解決方案,因為如果不移動,它將精確地模擬作用域變量的生命周期。 (我對std::shared_ptr非常懷疑;生存期應該是確定性的,而不取決於是否有人持有指向它的指針。我還可以想象網絡服務器將持有指向其客戶端的指針的情況,但存在循環風險。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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