在 C++ 中是按值传递还是按常量引用传递更好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/270408/
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
Is it better in C++ to pass by value or pass by constant reference?
提问by Matt Pascoe
Is it better in C++ to pass by value or pass by constant reference?
在 C++ 中是按值传递还是按常量引用传递更好?
I am wondering which is better practice. I realize that pass by constant reference should provide for better performance in the program because you are not making a copy of the variable.
我想知道哪种做法更好。我意识到通过常量引用传递应该在程序中提供更好的性能,因为您没有制作变量的副本。
采纳答案by Konrad Rudolph
It used to be generally recommended best practice1to use pass by const ref for all types, except for builtin types (char
, int
, double
, etc.), for iterators and for function objects(lambdas, classes deriving from std::*_function
).
它曾经被通常建议的最佳实践1至由常量REF使用通行证的所有类型,除了内建类型(char
,int
,double
等),用于迭代器和用于功能对象(lambda表达式,类从导出std::*_function
)。
This was especially true before the existence of move semantics. The reason is simple: if you passed by value, a copy of the object had to be made and, except for very small objects, this is always more expensive than passing a reference.
在移动语义出现之前尤其如此。原因很简单:如果您按值传递,则必须制作对象的副本,除了非常小的对象,这总是比传递引用更昂贵。
With C++11, we have gained move semantics. In a nutshell, move semantics permit that, in some cases, an object can be passed “by value” without copying it. In particular, this is the case when the object that you are passing is an rvalue.
使用 C++11,我们获得了移动语义。简而言之,移动语义允许在某些情况下,一个对象可以“按值”传递而无需复制它。特别是当您传递的对象是rvalue时就是这种情况。
In itself, moving an object is still at least as expensive as passing by reference. However, in many cases a function will internally copy an object anyway — i.e. it will take ownershipof the argument.2
就其本身而言,移动对象仍然至少与通过引用传递一样昂贵。然而,在许多情况下,函数无论如何都会在内部复制一个对象——即它会获得参数的所有权。2
In these situations we have the following (simplified) trade-off:
在这些情况下,我们有以下(简化的)权衡:
- We can pass the object by reference, then copy internally.
- We can pass the object by value.
- 我们可以通过引用传递对象,然后在内部复制。
- 我们可以按值传递对象。
“Pass by value” still causes the object to be copied, unless the object is an rvalue. In the case of an rvalue, the object can be moved instead, so that the second case is suddenly no longer “copy, then move” but “move, then (potentially) move again”.
“按值传递”仍然会导致对象被复制,除非对象是右值。在右值的情况下,可以改为移动对象,因此第二种情况突然不再是“复制,然后移动”而是“移动,然后(可能)再次移动”。
For large objects that implement proper move constructors (such as vectors, strings …), the second case is then vastlymore efficient than the first. Therefore, it is recommended to use pass by value if the function takes ownership of the argument, and if the object type supports efficient moving.
对于实施适当的移动的构造(如载体,字符串...)大的物体,第二壳体是则大大大于第一更有效。因此,如果函数拥有参数的所有权,并且对象类型支持有效移动,则建议使用按值传递。
A historical note:
历史记录:
In fact, any modern compiler should be able to figure out when passing by value is expensive, and implicitly convert the call to use a const ref if possible.
事实上,任何现代编译器都应该能够确定何时按值传递是昂贵的,并在可能的情况下将调用隐式转换为使用 const ref。
In theory.In practice, compilers can't always change this without breaking the function's binary interface. In some special cases (when the function is inlined) the copy will actually be elided if the compiler can figure out that the original object won't be changed through the actions in the function.
理论上。实际上,编译器不能总是在不破坏函数的二进制接口的情况下改变它。在某些特殊情况下(当函数被内联时),如果编译器可以确定原始对象不会通过函数中的操作更改,则副本实际上将被省略。
But in general the compiler can't determine this, and the advent of move semantics in C++ has made this optimisation much less relevant.
但通常编译器无法确定这一点,而 C++ 中移动语义的出现使这种优化变得不那么重要。
1E.g. in Scott Meyers, Effective C++.
1例如在 Scott Meyers,Effective C++ 中。
2This is especially often true for object constructors, which may take arguments and store them internally to be part of the constructed object's state.
2对于对象构造函数来说尤其如此,它可以接受参数并将它们存储在内部,作为构造对象状态的一部分。
回答by Johannes Schaub - litb
Edit:New article by Dave Abrahams on cpp-next:
编辑:Dave Abrahams 关于 cpp-next 的新文章:
Want speed? Pass by value.
想要速度?按值传递。
Pass by value for structs where the copying is cheap has the additional advantage that the compiler may assume that the objects don't alias (are not the same objects). Using pass-by-reference the compiler cannot assume that always. Simple example:
对于复制成本较低的结构,按值传递具有额外的优势,即编译器可以假定对象没有别名(不是相同的对象)。使用传递引用,编译器不能总是假设。简单的例子:
foo * f;
void bar(foo g) {
g.i = 10;
f->i = 2;
g.i += 5;
}
the compiler can optimize it into
编译器可以将其优化为
g.i = 15;
f->i = 2;
since it knows that f and g doesn't share the same location. if g was a reference (foo &), the compiler couldn't have assumed that. since g.i could then be aliased by f->i and have to have a value of 7. so the compiler would have to re-fetch the new value of g.i from memory.
因为它知道 f 和 g 不共享相同的位置。如果 g 是一个引用 (foo &),编译器就不会假设。因为 gi 可以被 f->i 取别名,并且必须具有 7 的值。所以编译器必须从内存中重新获取 gi 的新值。
For more pratical rules, here is a good set of rules found in Move Constructorsarticle (highly recommended reading).
有关更实用的规则,请参阅Move Constructors文章中的一组很好的规则(强烈推荐阅读)。
- If the function intends to change the argument as a side effect, take it by non-const reference.
- If the function doesn't modify its argument and the argument is of primitive type, take it by value.
- Otherwise take it by const reference, except in the following cases
- If the function would then need to make a copy of the const reference anyway, take it by value.
- 如果函数打算更改参数作为副作用,请通过非常量引用来获取它。
- 如果函数不修改其参数并且参数是原始类型,则按值获取它。
- 否则通过常量引用获取它,以下情况除外
- 如果该函数无论如何都需要制作 const 引用的副本,请按值获取它。
"Primitive" above means basically small data types that are a few bytes long and aren't polymorphic (iterators, function objects, etc...) or expensive to copy. In that paper, there is one other rule. The idea is that sometimes one wants to make a copy (in case the argument can't be modified), and sometimes one doesn't want (in case one wants to use the argument itself in the function if the argument was a temporary anyway, for example). The paper explains in detail how that can be done. In C++1x that technique can be used natively with language support. Until then, i would go with the above rules.
上面的“原始”意味着基本上是几个字节长的小数据类型,并且不是多态的(迭代器、函数对象等)或复制成本高。在那篇论文中,还有另一个规则。这个想法是有时人们想要复制一份(以防无法修改参数),有时又不想(以防万一人们想在函数中使用参数本身,如果参数无论如何都是临时的, 例如)。该论文详细解释了如何做到这一点。在 C++1x 中,该技术可以在语言支持下本地使用。在那之前,我会遵守上述规则。
Examples: To make a string uppercase and return the uppercase version, one should always pass by value: One has to take a copy of it anyway (one couldn't change the const reference directly) - so better make it as transparent as possible to the caller and make that copy early so that the caller can optimize as much as possible - as detailed in that paper:
示例:要使字符串大写并返回大写版本,应始终按值传递:无论如何都必须复制它(不能直接更改 const 引用)-因此最好使其尽可能透明调用者并尽早制作该副本,以便调用者可以尽可能地进行优化 - 如该论文中所述:
my::string uppercase(my::string s) { /* change s and return it */ }
However, if you don't need to change the parameter anyway, take it by reference to const:
但是,如果您无论如何都不需要更改参数,请通过引用 const 来获取它:
bool all_uppercase(my::string const& s) {
/* check to see whether any character is uppercase */
}
However, if you the purpose of the parameter is to write something into the argument, then pass it by non-const reference
但是,如果参数的目的是将某些内容写入参数,则通过非常量引用传递它
bool try_parse(T text, my::string &out) {
/* try to parse, write result into out */
}
回答by Lou Franco
Depends on the type. You are adding the small overhead of having to make a reference and dereference. For types with a size equal or smaller than pointers that are using the default copy ctor, it would probably be faster to pass by value.
取决于类型。您正在添加必须进行引用和取消引用的小开销。对于大小等于或小于使用默认复制构造函数的指针的类型,按值传递可能会更快。
回答by Torlack
As it has been pointed out, it depends on the type. For built-in data types, it is best to pass by value. Even some very small structures, such as a pair of ints can perform better by passing by value.
正如已经指出的那样,这取决于类型。对于内置数据类型,最好按值传递。即使是一些非常小的结构,例如一对整数,也可以通过按值传递来表现得更好。
Here is an example, assume you have an integer value and you want pass it to another routine. If that value has been optimized to be stored in a register, then if you want to pass it be reference, it first must be stored in memory and then a pointer to that memory placed on the stack to perform the call. If it was being passed by value, all that is required is the register pushed onto the stack. (The details are a bit more complicated than that given different calling systems and CPUs).
这是一个示例,假设您有一个整数值并且您想将它传递给另一个例程。如果该值已优化为存储在寄存器中,那么如果要将其作为引用传递,则必须首先将其存储在内存中,然后将指向该内存的指针放置在堆栈中以执行调用。如果它是按值传递的,则所需要的只是将寄存器压入堆栈。(细节比给定不同的调用系统和 CPU 稍微复杂一些)。
If you are doing template programming, you are usually forced to always pass by const ref since you don't know the types being passed in. Passing penalties for passing something bad by value are much worse than the penalties of passing a built-in type by const ref.
如果你在做模板编程,你通常被迫总是通过 const ref 传递,因为你不知道被传入的类型。传递错误的值的惩罚比传递内置类型的惩罚要糟糕得多通过常量引用。
回答by Martin G
This is what i normally work by when designing the interface of a non-template function:
这是我在设计非模板函数的接口时通常使用的方法:
Pass by value if the function does not want to modify the parameter and the value is cheap to copy (int, double, float, char, bool, etc... Notice that std::string, std::vector, and the rest of the containers in the standard library are NOT)
Pass by const pointer if the value is expensive to copy and the function does not want to modify the value pointed to and NULL is a value that the function handles.
Pass by non-const pointer if the value is expensive to copy and the function wants to modify the value pointed to and NULL is a value that the function handles.
Pass by const reference when the value is expensive to copy and the function does not want to modify the value referred to and NULL would not be a valid value if a pointer was used instead.
Pass by non-const reference when the value is expensive to copy and the function wants to modify the value referred to and NULL would not be a valid value if a pointer was used instead.
如果函数不想修改参数并且该值的复制成本很低(int、double、float、char、bool 等...请注意,std::string、std::vector 和其余的标准库中的容器不是)
如果值复制成本高且函数不想修改指向的值并且 NULL 是函数处理的值,则通过 const 指针传递。
如果复制值的开销很大并且函数想要修改指向的值并且 NULL 是函数处理的值,则通过非常量指针传递。
当值复制成本高且函数不想修改引用的值时,通过 const 引用传递,如果使用指针,NULL 将不是有效值。
当值复制成本很高并且函数想要修改引用的值并且如果使用指针代替时 NULL 将不是有效值时,通过非常量引用传递。
回答by GeekyMonkey
Sounds like you got your answer. Passing by value is expensive, but gives you a copy to work with if you need it.
听起来你得到了答案。按值传递很昂贵,但如果需要,可以为您提供一个副本。
回答by sergtk
As a rule passing by const reference is better. But if you need to modify you function argument locally you should better use passing by value. For some basic types the performance in general the same both for passing by value and by reference. Actually reference internally represented by pointer, that is why you can expect for instance that for pointer both passing are the same in terms of performance, or even passing by value can be faster because of needless dereference.
通常,通过 const 引用传递更好。但是,如果您需要在本地修改函数参数,则最好使用按值传递。对于某些基本类型,按值和按引用传递的性能通常相同。实际上引用在内部由指针表示,这就是为什么您可以期望例如对于指针传递在性能方面是相同的,或者由于不必要的取消引用,甚至按值传递可以更快。
回答by Peter
As a rule of thumb, value for non-class types and const reference for classes. If a class is really small it's probably better to pass by value, but the difference is minimal. What you really want to avoid is passing some gigantic class by value and having it all duplicated - this will make a huge difference if you're passing, say, a std::vector with quite a few elements in it.
根据经验,非类类型的值和类的常量引用。如果一个类真的很小,按值传递可能会更好,但差异很小。您真正想要避免的是通过值传递一些巨大的类并将其全部复制 - 如果您传递的是其中包含相当多元素的 std::vector ,这将产生巨大的差异。
回答by Germán Diago
Pass by value for small types.
小类型按值传递。
Pass by const references for big types (the definition of big can vary between machines) BUT, in C++11, pass by value if you are going to consume the data, since you can exploit move semantics. For example:
传递大类型的常量引用(big 的定义可能因机器而异)但是,在 C++11 中,如果您要使用数据,则通过值传递,因为您可以利用移动语义。例如:
class Person {
public:
Person(std::string name) : name_(std::move(name)) {}
private:
std::string name_;
};
Now the calling code would do:
现在调用代码会做:
Person p(std::string("Albert"));
And only one object would be created and moved directly into member name_
in class Person
. If you pass by const reference, a copy will have to be made for putting it into name_
.
并且只会创建一个对象并将其直接移动到name_
class 中的member中Person
。如果通过 const 引用传递,则必须制作一个副本才能将其放入name_
.
回答by Dhirendra Sengar
Simple difference :- In function we have input and output parameter , so if your passing input and out parameter is same then use call by reference else if input and output parameter are different then better to use call by value .
简单的区别:- 在函数中,我们有输入和输出参数,所以如果您传递的输入和输出参数相同,则使用按引用调用,否则如果输入和输出参数不同,则最好使用按值调用。
example void amount(int account , int deposit , int total )
例子 void amount(int account , int deposit , int total )
input parameter : account , deposit output paramteter: total
输入参数: account , deposit 输出参数: total
input and out is different use call by vaule
输入和输出是不同的,使用按值调用
void amount(int total , int deposit )
void amount(int total , int deposit )
input total deposit output total
投入总存款 产出总