C++ 将共享指针作为参数传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10826541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing shared pointers as arguments
提问by Steve H
If I declare an object wrapped in a shared pointer:
如果我声明一个包含在共享指针中的对象:
std::shared_ptr<myClass> myClassObject(new myClass());
then I wanted to pass it as an argument to a method:
然后我想将它作为参数传递给一个方法:
DoSomething(myClassObject);
//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
arg1->someField = 4;
}
Does the above simply increment the shared_pt's reference count and everything is cool? Or does it leave a dangling pointer?
以上是否只是增加了 shared_pt 的引用计数,一切都很酷?或者它是否留下了一个悬空指针?
Are you still supposed to do this?:
你还应该这样做吗?:
DoSomething(myClassObject.Get());
void DoSomething(std::shared_ptr<myClass>* arg1)
{
(*arg1)->someField = 4;
}
I think that the 2nd way may be more efficient because it only has to copy 1 address (as opposed to the whole smart pointer), but the 1st way seems more readable and I do not anticipate pushing performance limits. I just want to make sure there's not something dangerous about it.
我认为第二种方式可能更有效,因为它只需要复制 1 个地址(而不是整个智能指针),但第一种方式似乎更具可读性,我不希望推动性能限制。我只是想确保它没有危险。
Thank you.
谢谢你。
回答by R. Martinho Fernandes
I want to pass a shared pointer to a function. Can you help me with that?
我想将共享指针传递给函数。你能帮我解决这个问题吗?
Sure, I can help with you that. I assume you have some understanding of ownership semantics in C++. Is that true?
当然,我可以帮你。我假设您对 C++ 中的所有权语义有一些了解。真的吗?
Yeah, I'm reasonably comfortable with the subject.
是的,我对这个主题相当满意。
Good.
好的。
Ok, I can only think of two reasons to take a shared_ptr
argument:
好吧,我只能想到两个理由来shared_ptr
争论:
- The function wants to share ownership of the object;
- The function does some operation that works specifically on
shared_ptr
s.
- 函数想要共享对象的所有权;
- 该函数执行一些专门对
shared_ptr
s起作用的操作。
Which one are you interested in?
你对哪一个感兴趣?
I'm looking for a general answer, so I'm actually interested in both. I'm curious about what you mean in case #2, though.
我正在寻找一个通用的答案,所以我实际上对两者都感兴趣。不过,我很好奇你在案例#2 中的意思。
Examples of such functions include std::static_pointer_cast
, custom comparators, or predicates. For example, if you need to find all unique shared_ptr from a vector, you need such a predicate.
此类函数的示例包括std::static_pointer_cast
、自定义比较器或谓词。例如,如果您需要从一个向量中找到所有唯一的 shared_ptr,您就需要这样一个谓词。
Ah, when the function actually needs to manipulate the smart pointer itself.
啊,当函数实际上需要操作智能指针本身时。
Exactly.
确切地。
In that case, I think we should pass by reference.
在那种情况下,我认为我们应该通过引用传递。
Yes. And if it doesn't change the pointer, you want to pass by const reference. There's no need to copy since you don't need to share ownership. That's the other scenario.
是的。如果它不改变指针,你想通过常量引用传递。无需复制,因为您不需要共享所有权。那是另一种情况。
Ok, got it. Let's talk about the other scenario.
好的,我知道了。让我们谈谈另一种情况。
The one where you share the ownership? Ok. How do you share ownership with shared_ptr
?
您共享所有权的那个?好的。您如何与 分享所有权shared_ptr
?
By copying it.
通过复制它。
Then the function will need to make a copy of a shared_ptr
, correct?
那么该函数将需要复制 a shared_ptr
,对吗?
Obviously. So I pass it by a reference to const and copy to a local variable?
明显地。所以我通过对 const 的引用传递它并复制到局部变量?
No, that's a pessimization. If it is passed by reference, the function will have no choice but to make the copy manually. If it is passed by value the compiler will pick the best choice between a copy and a move and perform it automatically. So, pass by value.
不,那是悲观。如果它是通过引用传递的,则该函数将别无选择,只能手动进行复制。如果按值传递,编译器将在复制和移动之间选择最佳选择并自动执行。所以,按值传递。
Good point. I must remember that "Want Speed? Pass by Value." article more often.
Wait, what if the function stores the
shared_ptr
in a member variable, for example? Won't that make a redundant copy?
好点子。我必须经常记住“想要速度?通过价值。”文章。
等等,例如,如果函数将 存储
shared_ptr
在成员变量中怎么办?这不会产生多余的副本吗?
The function can simply move the shared_ptr
argument into its storage. Moving a shared_ptr
is cheap because it doesn't change any reference counts.
该函数可以简单地将shared_ptr
参数移动到其存储中。移动 ashared_ptr
很便宜,因为它不会改变任何引用计数。
Ah, good idea.
But I'm thinking of a third scenario: what if you don't want to manipulate the
shared_ptr
, nor to share ownership?
啊,好主意。
但我正在考虑第三种情况:如果您不想操纵
shared_ptr
,也不想共享所有权怎么办?
In that case, shared_ptr
is completely irrelevant to the function. If you want to manipulate the pointee, take a pointee, and let the callers pick what ownership semantics they want.
在那种情况下,shared_ptr
与函数完全无关。如果您想操作指针对象,请获取指针对象,然后让调用者选择他们想要的所有权语义。
And should I take the pointee by reference or by value?
我应该通过引用还是通过价值来获取指针?
The usual rules apply. Smart pointers don't change anything.
通常的规则适用。智能指针不会改变任何东西。
Pass by value if I'm going to copy, pass by reference if I want to avoid a copy.
如果我要复制,则按值传递,如果我想避免复制,则按引用传递。
Right.
对。
Hmm. I think you forgot yet another scenario. What if I want to share ownership, but only depending on a certain condition?
唔。我想你忘记了另一个场景。如果我想共享所有权,但只取决于特定条件怎么办?
Ah, an interesting edge case. I don't expect that to happen often. But when it happens you can either pass by value and ignore the copy if you don't need it, or pass by reference and make the copy if you need it.
啊,一个有趣的边缘案例。我不希望这种情况经常发生。但是当它发生时,您可以通过值传递并在不需要时忽略副本,或者在需要时通过引用传递并制作副本。
I risk one redundant copy in the first option, and lose a potential move in the second. Can't I eat the cake and have it too?
我在第一个选项中冒着一个冗余副本的风险,而在第二个选项中失去了一个潜在的移动。我不能吃蛋糕也吃吗?
If you're in a situation where that really matters, you can provide two overloads, one taking a const lvalue reference, and another taking an rvalue reference. One copies, the other moves. A perfect-forwarding function template is another option.
如果您处于真正重要的情况下,您可以提供两种重载,一种采用 const 左值引用,另一种采用右值引用。一个复制,另一个移动。完美转发功能模板是另一种选择。
I think that covers all the possible scenarios. Thank you very much.
我认为这涵盖了所有可能的情况。非常感谢。
回答by Mark Ransom
I think people are unnecessarily scared of using raw pointers as function parameters. If the function is not going to store the pointer or otherwise affect its lifetime, a raw pointer works just as well and represents the lowest common denominator. Consider for example how you would pass a unique_ptr
into a function that takes a shared_ptr
as a parameter, either by value or by const reference?
我认为人们不必要地害怕使用原始指针作为函数参数。如果函数不打算存储指针或以其他方式影响其生命周期,则原始指针也能正常工作并表示最小公分母。例如,考虑如何将 a 传递给unique_ptr
将 ashared_ptr
作为参数的函数,无论是按值还是按常量引用?
void DoSomething(myClass * p);
DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());
A raw pointer as a function parameter does not prevent you from using smart pointers in the calling code, where it really matters.
作为函数参数的原始指针不会阻止您在调用代码中使用智能指针,因为它确实很重要。
回答by R Samuel Klatchko
Yes, the entire idea about a shared_ptr<> is that multiple instances can hold the same raw pointer and the underlying memory will only be freed when there the last instance of shared_ptr<> is destroyed.
是的,关于 shared_ptr<> 的整个想法是多个实例可以保存相同的原始指针,并且只有当 shared_ptr<> 的最后一个实例被销毁时才会释放底层内存。
I would avoid a pointer to a shared_ptr<> as that defeats the purpose as you are now dealing with raw_pointers again.
我会避免使用指向 shared_ptr<> 的指针,因为这违背了您现在再次处理 raw_pointers 的目的。
回答by djechlin
Passing-by-value in your first example is safe but there is a better idiom. Pass by const reference when possible - I would say yes even when dealing with smart pointers. Your second example is not exactly broken but it's very !???
. Silly, not accomplishing anything and defeats part of the point of smart pointers, and going to leave you in a buggy world of pain when you try to dereference and modify things.
在您的第一个示例中按值传递是安全的,但有一个更好的习惯用法。尽可能通过 const 引用 - 即使在处理智能指针时我也会说是。您的第二个示例并未完全损坏,但它非常!???
. 愚蠢的,没有完成任何事情并破坏了智能指针的部分意义,并且当您尝试取消引用和修改事物时,会让您陷入痛苦的世界。
回答by organicoman
in your function
DoSomething
you are changing a data member of an instance of class myClass
so what you are modifying is the managed (raw pointer) object not the (shared_ptr) object. Which means at the return point of this function all shared pointers to the managed raw pointer will see their data member: myClass::someField
changed to a different value.
在您的函数中,
DoSomething
您正在更改类实例的数据成员,myClass
因此您正在修改的是托管(原始指针)对象而不是(shared_ptr)对象。这意味着在此函数的返回点,所有指向托管原始指针的共享指针都将看到它们的数据成员:myClass::someField
更改为不同的值。
in this case, you are passing an object to a function with the guarantee that you are not modifying it (talking about shared_ptr not the owned object).
在这种情况下,您将一个对象传递给一个函数,并保证您不会修改它(谈论的是 shared_ptr 而不是拥有的对象)。
The idiom to express this is through: a const ref, like so
表达这一点的习惯用法是:a const ref,像这样
void DoSomething(const std::shared_ptr<myClass>& arg)
void DoSomething(const std::shared_ptr<myClass>& arg)
Likewise you are assuring the user of your function, that you are not adding another owner to the list of owners of the raw pointer. However, you kept the possibility to modify the underlying object pointed to by the raw pointer.
同样,您向函数的用户保证,您不会将另一个所有者添加到原始指针的所有者列表中。但是,您保留了修改原始指针指向的底层对象的可能性。
CAVEAT: Which means, if by some means someone calls shared_ptr::reset
before you call your function, and at that moment it is the last shared_ptr owning the raw_ptr, then your object will be destroyed, and your function will manipulate a dangling Pointer to destroyed object. VERY DANGEROUS!!!
CAVEAT:这意味着,如果通过某种方式有人shared_ptr::reset
在您调用您的函数之前调用,并且此时它是拥有 raw_ptr 的最后一个 shared_ptr,那么您的对象将被销毁,您的函数将操纵一个悬空指针指向被销毁的对象。非常危险!!!