C++ 在 getter 函数中返回 const 引用还是副本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2182408/
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
Return a const reference or a copy in a getter function?
提问by cairol
What's better as default, to return a copy (1) or a reference (2) from a getter function?
默认情况下,从 getter 函数返回副本 (1) 或引用 (2)哪个更好?
class foo {
public:
std::string str () { // (1)
return str_;
}
const std::string& str () { // (2)
return str_;
}
private:
std::string str_;
};
I know 2) could be faster but don't have to due to (N)RVO. 1) is safer concerning dangling references but the object will probably outlife or the reference is never stored.
我知道 2) 可能会更快,但不必由于 (N)RVO。1) 关于悬空引用更安全,但对象可能会过期或永远不会存储引用。
What's your default when you write a class and don't know (yet) whether performance and lifetime issues matter?
当您编写一个类并且不知道(还)性能和生命周期问题是否重要时,您的默认设置是什么?
Additional question: Does the game change when the member is not a plain string but rather a vector?
附加问题:当成员不是普通字符串而是向量时,游戏会改变吗?
采纳答案by cairol
Well it really depends on what you expect the behaviourto be, by default.
嗯,默认情况下,这实际上取决于您期望的行为。
Do you expect the caller to see changes made to str_ unbeknownst(what a word!) to them? Then you need to pass back a reference. Might be good if you can have a refcounted data member and return that.
您是否希望调用者看到对 str_ unbeknownst(什么是一个词!)所做的更改?然后你需要传回一个引用。如果您可以拥有一个 refcounted 数据成员并返回它,那可能会很好。
If you expect the caller to get a copy, do 1).
如果您希望来电者获得一份副本,请执行 1)。
回答by Naveen
My rule of thumb is to return a copy for simple basic datatypes such as int, string etc. For a bit more complicated structures where copying may be costlier (like vector you mentioned) I prefer to return a const-reference.
我的经验法则是为简单的基本数据类型(如 int、string 等)返回一个副本。对于复制可能更昂贵的更复杂的结构(如您提到的向量),我更喜欢返回一个常量引用。
回答by David Rodríguez - dribeas
The compiler will not be able to perform (N)RVO in this case. The (named) return value optimization is an optimization where the compiler creates the function auto variables in the place of the return value to avoid having to copy:
在这种情况下,编译器将无法执行 (N)RVO。(命名)返回值优化是一种优化,其中编译器在返回值的位置创建函数自动变量以避免必须复制:
std::string f()
{
std::string result;
//...
return result;
}
When the compiler sees the code above (and assuming that if any other return is present it will also return the result
variable) it knows that the variable result
has as only possible fate being copied over the returned temporary and then destroyed. The compiler can then remove the result
variable altogether and use the return temporary as the only variable. I insist: the compiler does not remove the return temporary, it removes the local function variable. The return temporary is required to fulfill the compilers call convention.
当编译器看到上面的代码时(并假设如果存在任何其他返回值,它也将返回该result
变量),它知道该变量result
唯一可能的命运是被复制到返回的临时对象上,然后被销毁。然后编译器可以result
完全删除该变量并使用返回临时变量作为唯一的变量。我坚持:编译器不会删除返回临时值,它会删除局部函数变量。返回临时需要满足编译器调用约定。
When you are returning a member of your class, the member must exist, and the call convention requires the returned object to be in a particular location (stack address usually). The compiler cannot create the method attribute over the returned object location, nor can it elide making the copy.
当您返回类的成员时,该成员必须存在,并且调用约定要求返回的对象位于特定位置(通常是堆栈地址)。编译器不能在返回的对象位置上创建方法属性,也不能省略复制。
回答by Johannes Schaub - litb
I'm returning a reference, because a string seems not "cheap to copy" to me. It's a complex data type with dynamic memory management and all that.
我正在返回一个引用,因为一个字符串对我来说似乎并不“便宜”。它是一种复杂的数据类型,具有动态内存管理等功能。
The "if you want the caller to get a copy, you should return by value" argument is moot, because it doesn't preclude copies at all. The caller can still do the following and get a copy anyway
“如果你想让调用者得到一个副本,你应该按值返回”这个论点是没有实际意义的,因为它根本不排除副本。调用者仍然可以执行以下操作并获取副本
string s = obj.str();
You need to explicitly create a reference on the caller side to be able to refer to the data member directly afterwards - but why would you do that? There definitely are enough user defined types that are cheap to copy
您需要在调用方显式创建一个引用,以便能够在之后直接引用数据成员 - 但为什么要这样做呢?肯定有足够多的用户定义的类型可以廉价复制
- Smart Pointers
- Iterators
- All of the non-class types.
- 智能指针
- 迭代器
- 所有非类类型。
回答by ergosys
Returning a reference to an object's internals as part of its public interface can be a code smell if not outright bad design.
将对象内部的引用作为其公共接口的一部分返回可能是一种代码味道,如果不是完全糟糕的设计的话。
Before returning a reference to an internal object in a public interface, the designer should pause. Doing so couples users of your class to part of your design. Often it is outright unnecessary, sometimes it indicates further design work is needed. At times it is necessary, as commenters have noted.
在返回对公共接口中的内部对象的引用之前,设计者应该暂停。这样做会将类的用户与设计的一部分结合起来。通常它是完全没有必要的,有时它表明需要进一步的设计工作。正如评论者所指出的,有时这是必要的。
回答by ur.
If there is no special reason to use a value type as return value, I always return a const reference. If I need (or expect to need) a (writable) copy, I add a copy ctor and an assignment operator to the returned class if not already available. For the usage think of:
如果没有特殊原因使用值类型作为返回值,我总是返回一个 const 引用。如果我需要(或期望需要)一个(可写的)副本,我会向返回的类添加一个复制构造函数和一个赋值运算符(如果尚不可用)。对于用法,请考虑:
const MyClass & ref = container.GetAt( 1234 ); // need only reference
MyClass copy = container.GetAt( 1234 ); // get writable copy
Actually this is quite straight forward, isn't it?
其实这很直接,不是吗?
回答by ScaryAardvark
The only problem I have with returning a const-reference, which is something I would typically do for non basic types, is that there is nothing to stop the caller removing the "const"ness and then modifying the value.
我在返回常量引用时遇到的唯一问题,这是我通常对非基本类型所做的事情,是没有什么可以阻止调用者删除“常量”然后修改值。
Personally, I'd suggest that such code is a bug. If they know you're returning a reference and continue to cast away the const then it's on their head.
就个人而言,我建议这样的代码是一个错误。如果他们知道你正在返回一个引用并继续抛弃 const 那么它就在他们的头上。
回答by Will
if its a small basic type - primatives like int and long and their wrappers and other basic things like 'Point' - return a copy
if its a string, or any other complex type - return a reference.
如果它是一个小的基本类型——像 int 和 long 这样的原始类型及其包装器和其他基本的东西,比如“Point”——返回一个副本
如果它是一个string或任何其他复杂类型 - 返回一个引用。