在 C++11 中,按值传递是合理的默认值吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7592630/
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 pass-by-value a reasonable default in C++11?
提问by Derek Thurn
In traditional C++, passing by value into functions and methods is slow for large objects, and is generally frowned upon. Instead, C++ programmers tend to pass references around, which is faster, but which introduces all sorts of complicated questions around ownership and especially around memory management (in the event that the object is heap-allocated)
在传统的 C++ 中,将值传递给函数和方法对于大对象来说很慢,而且通常是不受欢迎的。相反,C++ 程序员倾向于传递引用,这会更快,但会引入各种有关所有权的复杂问题,尤其是内存管理(如果对象是堆分配的)
Now, in C++11, we have Rvalue references and move constructors, which mean that it's possible to implement a large object (like an std::vector
) that's cheap to pass by value into and out of a function.
现在,在 C++11 中,我们有 Rvalue 引用和移动构造函数,这意味着可以实现一个大对象(如std::vector
),通过值传入和传出函数的成本很低。
So, does this mean that the default should be to pass by value for instances of types such as std::vector
and std::string
? What about for custom objects? What's the new best practice?
那么,这是否意味着默认值应该是按值传递诸如std::vector
and之类的类型的实例std::string
?自定义对象呢?什么是新的最佳实践?
采纳答案by Luc Danton
It's a reasonable default ifyou need to make a copy inside the body. This is what Dave Abrahams is advocating:
如果您需要在正文中制作副本,这是一个合理的默认设置。这就是 Dave Abrahams所提倡的:
Guideline: Don't copy your function arguments. Instead, pass them by value and let the compiler do the copying.
指南:不要复制你的函数参数。相反,按值传递它们并让编译器进行复制。
In code this means don't do this:
在代码中,这意味着不要这样做:
void foo(T const& t)
{
auto copy = t;
// ...
}
but do this:
但这样做:
void foo(T t)
{
// ...
}
which has the advantage that the caller can use foo
like so:
它的优点是调用者可以foo
像这样使用:
T lval;
foo(lval); // copy from lvalue
foo(T {}); // (potential) move from prvalue
foo(std::move(lval)); // (potential) move from xvalue
and only minimal work is done. You'd need two overloads to do the same with references, void foo(T const&);
and void foo(T&&);
.
并且只完成了最少的工作。您需要两个重载才能对引用执行相同操作,void foo(T const&);
而void foo(T&&);
.
With that in mind, I now wrote my valued constructors as such:
考虑到这一点,我现在编写了我的重要构造函数:
class T {
U u;
V v;
public:
T(U u, V v)
: u(std::move(u))
, v(std::move(v))
{}
};
Otherwise, passing by reference to const
still is reasonable.
否则,通过引用传递给const
仍然是合理的。
回答by Ayjay
In almost all cases, your semantics should be either:
在几乎所有情况下,您的语义应该是:
bar(foo f); // want to obtain a copy of f
bar(const foo& f); // want to read f
bar(foo& f); // want to modify f
All other signatures should be used only sparingly, and with good justification. The compiler will now pretty much always work these out in the most efficient way. You can just get on with writing your code!
所有其他签名都应该谨慎使用,并有充分的理由。编译器现在几乎总是以最有效的方式解决这些问题。您可以继续编写代码!
回答by Edward Brey
Pass parameters by value if inside the function body you need a copy of the object or only need to move the object. Pass by const&
if you only need non-mutating access to the object.
如果在函数体内需要对象的副本或只需要移动对象,则按值传递参数。擦肩而过const&
如果你只需要非突变访问对象。
Object copy example:
对象复制示例:
void copy_antipattern(T const& t) { // (Don't do this.)
auto copy = t;
t.some_mutating_function();
}
void copy_pattern(T t) { // (Do this instead.)
t.some_mutating_function();
}
Object move example:
对象移动示例:
std::vector<T> v;
void move_antipattern(T const& t) {
v.push_back(t);
}
void move_pattern(T t) {
v.push_back(std::move(t));
}
Non-mutating access example:
非变异访问示例:
void read_pattern(T const& t) {
t.some_const_function();
}
For rationale, see these blog posts by Dave Abrahamsand Xiang Fan.
有关基本原理,请参阅Dave Abrahams和向凡撰写的这些博客文章。
回答by Patrick Fromberg
The signature of a function should reflect it's intended use. Readability is important, also for the optimizer.
函数的签名应该反映它的预期用途。可读性很重要,对于优化器也是如此。
This is the best precondition for an optimizer to create fastest code - in theory at least and if not in reality then in a few years reality.
这是优化器创建最快代码的最佳先决条件 - 至少在理论上,如果不是在现实中,那么在几年内是现实。
Performance considerations are very often overrated in the context of parameter passing. Perfect forwarding is an example. Functions like emplace_back
are mostly very short and inlined anyway.
在参数传递的上下文中,性能考虑因素经常被高估。完美转发就是一个例子。emplace_back
无论如何,像这样的函数通常非常短且内联。