簡體   English   中英

將共享指針作為參數傳遞

[英]Passing shared pointers as arguments

如果我聲明一個包含在共享指針中的對象:

std::shared_ptr<myClass> myClassObject(new myClass());

然后我想將它作為參數傳遞給一個方法:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

以上是否只是增加了 shared_pt 的引用計數,一切都很酷? 或者它是否留下了一個懸空指針?

你還應該這樣做嗎?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

我認為第二種方式可能更有效,因為它只需要復制 1 個地址(而不是整個智能指針),但第一種方式似乎更具可讀性,我不希望推動性能限制。 我只是想確保它沒有危險。

謝謝你。

我想將共享指針傳遞給函數。 你能幫我解決這個問題嗎?

當然,我可以幫你。 我假設您對 C++ 中的所有權語義有一些了解。 真的嗎?

是的,我對這個主題相當滿意。

好的。

好吧,我只能想到采用shared_ptr參數的兩個原因:

  1. 函數想要共享對象的所有權;
  2. 該函數執行一些專門用於shared_ptr的操作。

你對哪一個感興趣?

我正在尋找一個通用的答案,所以我實際上對兩者都感興趣。 不過,我很好奇你在案例#2 中的意思。

此類函數的示例包括std::static_pointer_cast 、自定義比較器或謂詞。 例如,如果您需要從一個向量中找到所有唯一的 shared_ptr,您就需要這樣一個謂詞。

啊,當函數實際上需要操作智能指針本身時。

確切地。

在那種情況下,我認為我們應該通過引用傳遞。

是的。 如果它不改變指針,你想通過常量引用傳遞。 無需復制,因為您不需要共享所有權。 那是另一種情況。

好的,我知道了。 讓我們談談另一種情況。

您共享所有權的那個? 行。 你如何與shared_ptr共享所有權?

通過復制它。

然后該函數需要復制shared_ptr ,對嗎?

明顯地。 所以我通過對 const 的引用傳遞它並復制到局部變量?

不,那是悲觀。 如果它是通過引用傳遞的,則該函數將別無選擇,只能手動進行復制。 如果按值傳遞,編譯器將在復制和移動之間選擇最佳選擇並自動執行。 所以,按值傳遞。

好點子。 我必須經常記住“ 想要速度?通過價值。 ”文章。

等等,例如,如果函數將shared_ptr存儲在成員變量中怎么辦? 這不會產生多余的副本嗎?

該函數可以簡單地將shared_ptr參數移動到其存儲中。 移動shared_ptr很便宜,因為它不會改變任何引用計數。

啊,好主意。

但我正在考慮第三種情況:如果您不想操作shared_ptr ,也不想共享所有權怎么辦?

在這種情況下, shared_ptr與函數完全無關。 如果您想操作指針對象,請獲取指針對象,然后讓調用者選擇他們想要的所有權語義。

我應該通過引用還是通過價值來獲取指針?

通常的規則適用。 智能指針不會改變任何東西。

如果我要復制,則按值傳遞,如果我想避免復制,則按引用傳遞。

對。

唔。 我想你忘記了另一個場景。 如果我想共享所有權,但只取決於特定條件怎么辦?

啊,一個有趣的邊緣案例。 我不希望這種情況經常發生。 但是當它發生時,您可以通過值傳遞並在不需要時忽略副本,或者在需要時通過引用傳遞並制作副本。

我在第一個選項中冒着一個冗余副本的風險,而在第二個選項中失去了一個潛在的移動。 我不能吃蛋糕也吃嗎?

如果您處於真正重要的情況下,您可以提供兩種重載,一種采用 const 左值引用,另一種采用右值引用。 一個復制,另一個移動。 完美轉發功能模板是另一種選擇。

我認為這涵蓋了所有可能的情況。 非常感謝你。

我認為人們不必要地害怕使用原始指針作為函數參數。 如果函數不打算存儲指針或以其他方式影響其生命周期,則原始指針也能正常工作並表示最小公分母。 例如,考慮如何將unique_ptr傳遞給將shared_ptr作為參數的函數,無論是通過值還是通過常量引用?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());

作為函數參數的原始指針不會阻止您在調用代碼中使用智能指針,因為它確實很重要。

是的,關於 shared_ptr<> 的整個想法是多個實例可以保存相同的原始指針,並且只有在 shared_ptr<> 的最后一個實例被銷毀時才會釋放底層內存。

我會避免使用指向 shared_ptr<> 的指針,因為這違背了您現在再次處理 raw_pointers 的目的。

在您的第一個示例中按值傳遞是安全的,但有一個更好的習慣用法。 盡可能通過 const 引用 - 即使在處理智能指針時我也會說是。 你的第二個例子並沒有完全壞掉,但它非常!??? . 愚蠢的,沒有完成任何事情並破壞了智能指針的部分意義,並且當您嘗試取消引用和修改事物時,會讓您陷入痛苦的世界。

在您的函數DoSomething您正在更改myClass類實例的數據成員,因此您正在修改的是托管(原始指針)對象而不是(shared_ptr)對象。 這意味着在此函數的返回點,所有指向托管原始指針的共享指針都將看到它們的數據成員: myClass::someField更改為不同的值。

在這種情況下,您將一個對象傳遞給一個函數,並保證您不會修改它(談論的是 shared_ptr 而不是擁有的對象)。

表達這一點的習慣用法是:a const ref,像這樣

void DoSomething(const std::shared_ptr<myClass>& arg)

同樣,您向函數的用戶保證,您不會將另一個所有者添加到原始指針的所有者列表中。 但是,您保留了修改原始指針指向的底層對象的可能性。

警告:這意味着,如果通過某種方式有人在你調用你的函數之前調用了shared_ptr::reset ,並且此時它是最后一個擁有 raw_ptr 的 shared_ptr,那么你的對象將被銷毀,你的函數將操縱一個懸空的指針到銷毀的對象。 非常危險!!!

暫無
暫無

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

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