将共享指针作为参数传递

Ste*_*e H 82 c++ c++-faq shared-ptr c++11

如果我声明一个包装在共享指针中的对象:

std::shared_ptr<myClass> myClassObject(new myClass());
Run Code Online (Sandbox Code Playgroud)

然后我想将它作为参数传递给方法:

DoSomething(myClassObject);

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

以上只是增加了shared_pt的引用计数,一切都很酷吗?还是留下一个悬垂的指针?

你还是应该这样做吗?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}
Run Code Online (Sandbox Code Playgroud)

我认为第二种方式可能更有效,因为它只需要复制1个地址(而不是整个智能指针),但第一种方式似乎更具可读性,我不期望推动性能限制.我只是想确保没有危险的东西.

谢谢.

R. *_*des 160

我想传递一个函数的共享指针.你能帮帮我吗?

当然,我可以帮助你.我假设您对C++中的所有权语义有一定的了解.真的吗?

是的,我对这个主题感到相当舒服.

好.

好吧,我只能想出两个理由来shared_ptr争论:

  1. 该函数想要共享对象的所有权;
  2. 该函数执行一些特定于shared_ptrs的操作.

你对哪一个感兴趣?

我正在寻找一般答案,所以我实际上对两者都感兴趣.不过,我很好奇你在#2的情况下的意思.

此类函数的示例包括std::static_pointer_cast自定义比较器或谓词.例如,如果您需要从向量中找到所有唯一的shared_ptr,则需要这样的谓词.

啊,当函数实际需要操纵智能指针本身时.

究竟.

在这种情况下,我认为我们应该通过参考.

是.如果它没有改变指针,你想传递const引用.由于您不需要共享所有权,因此无需复制.那是另一种情况.

好的,我知道了.我们来谈谈另一个场景.

您分享所有权的那个?好.你如何分享所有权shared_ptr

通过复制它.

那么函数需要复制一个shared_ptr,对吗?

明显.所以我通过引用const传递它并复制到局部变量?

不,这是一种悲观情绪.如果通过引用传递,该函数将别无选择,只能手动进行复制.如果按值传递,编译器将在副本和移动之间选择最佳选择并自动执行.所以,传递价值.

好点子.我必须记住" 想要速度?通过价值传递. "这篇文章更频繁.

等等,如果函数存储shared_ptr在成员变量中,该怎么办?这不会成为冗余副本吗?

该函数可以简单地将shared_ptr参数移动到其存储中.移动a shared_ptr很便宜,因为它不会改变任何引用计数.

啊,好主意.

但我想的是第三种情况:如果你不想操纵shared_ptr,也不想分享所有权怎么办?

在这种情况下,shared_ptr与功能完全无关.如果你想操纵指针,请指点,让调用者选择他们想要的所有权语义.

我应该通过引用还是通过值来引用指针?

通常的规则适用.智能指针不会改变任何东西.

如果我要复制,则按值传递,如果我想避免复制,则按引用传递.

对.

嗯.我想你又忘了另一个场景.如果我想分享所有权,但仅取决于某种条件,该怎么办?

啊,一个有趣的边缘案例.我不希望经常发生这种情况.但是当它发生时你可以通过值传递并在不需要时忽略副本,或者通过引用传递并在需要时制作副本.

我在第一个选项中冒一个冗余副本的风险,并在第二个选项中失去一个潜在的移动.我不能吃蛋糕也吃吗?

如果你处于真正重要的情况,你可以提供两个重载,一个采用const左值引用,另一个采用右值引用.一个副本,另一个移动.完美转发功能模板是另一种选择.

我认为这涵盖了所有可能的情况.非常感谢你.

  • 因为散文喜欢"这是否意味着我会通过引用const来传递它来制作副本?不,这是一种悲观情绪"让初学者感到困惑.通过对const的引用传递不会复制. (8认同)
  • +1,太棒了.但是,缺少手绘明星.:P (6认同)
  • @Jon:为了什么?这就是我应该做_A_还是应该做_B_.我想我们都知道如何通过值/引用传递对象,不是吗? (2认同)

Mar*_*som 18

我认为人们不必担心使用原始指针作为函数参数.如果函数不会存储指针或以其他方式影响其生命周期,则原始指针也可以正常工作并表示最小公分母.例如,考虑如何通过值或const引用unique_ptr将a shared_ptr作为参数传递给函数?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());
Run Code Online (Sandbox Code Playgroud)

作为函数参数的原始指针不会阻止您在调用代码中使用智能指针,这非常重要.

  • 如果您正在使用指针,为什么不使用引用呢?`DoSomething的(*a_smart_ptr)` (8认同)
  • @Xeo,你是对的 - 那会更好.有时你需要允许NULL指针的可能性. (5认同)
  • @AndreasMagnusson:当处理从另一个源传入的指针时,指针作为输出参数约定会给出错误的安全感.因为在这种情况下,调用很有趣(x)并且*x被修改,并且源没有&x来警告你. (2认同)

R S*_*hko 5

是的,关于shared_ptr<>的整个想法是多个实例可以保存相同的原始指针,并且只有当shared_ptr<>的最后一个实例被销毁时,底层内存才会被释放。

我会避免使用指向shared_ptr<>的指针,因为这违背了你现在再次处理raw_pointers的目的。