wrh*_*all 15 c++ pass-by-reference pass-by-value
两者之间是否存在功能差异:
void foo(const Bar& bar) {
Bar bar_copy(bar);
// Do stuff with bar_copy
}
Run Code Online (Sandbox Code Playgroud)
和
void foo(Bar bar) {
// Do stuff with bar
}
Run Code Online (Sandbox Code Playgroud)
Dre*_*ann 22
是的,有一个很有价值的区别.
void foo(Bar bar)可以复制构造或移动构造bar,具体取决于调用上下文.
当传递临时值时foo(Bar bar),您的编译器可能能够直接构造临时位置bar.帽子提示模板男孩.
您的功能void foo(const Bar& bar)始终执行副本.
您的功能void foo(Bar bar) 可能会执行复制或移动,也可能两者都不执行.
gha*_*.st 13
是的,存在差异.虽然最明显的一个是函数的类型发生了变化(因而也就是函数指针的类型),但也有一些不太明显的含义:
Bar例如,假设以下调用foo:
foo(Bar());
Run Code Online (Sandbox Code Playgroud)
对于第一个版本,这将通过引用传递const bar,然后使用复制构造函数进行复制.对于第二个版本,编译器将首先尝试move-constructor.
这意味着,唯一的第二个版本可以由仅可移动构造的类型调用,例如std::unique_ptr.实际上,手动强制复制甚至不允许编译该功能.
显然,这可以通过添加一个轻微的复杂性来减轻:
void foo(Bar&& bar) {
// Do something with bar.
// As it is an rvalue-reference, you need not copy it.
}
void foo(Bar const& bar) {
Bar bar_copy(bar);
foo(std::move(bar_copy));
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,还有另一个不同之处:检查访问权限的上下文.
请考虑以下事项Bar:
class Bar
{
Bar(Bar const&) = default;
Bar(Bar&&) = default;
public:
Bar() = default;
friend int main();
};
Run Code Online (Sandbox Code Playgroud)
现在,引用和复制版本将出错,而参数值为版本不会抱怨:
void fooA(const Bar& bar)
{
//Bar bar_copy(bar); // error: 'constexpr Bar::Bar(const Bar&)' is private
}
void fooB(Bar bar) { } // OK
Run Code Online (Sandbox Code Playgroud)
由于我们已宣布main为朋友,因此允许以下呼叫(请注意,如果实际呼叫是在static成员函数中进行的话,则不需要该朋友Bar):
int main()
{
fooB(Bar()); // OK: Main is friend
}
Run Code Online (Sandbox Code Playgroud)
Bar呼叫站点的完整性正如在评论中所观察到的,如果您希望在呼叫站点Bar上成为不完整类型,则可以使用传递引用版本,因为这不需要呼叫站点能够分配对象类型.Bar
C++ 11 12.8/31:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使该对象的复制/移动构造函数和/或析构函数具有副作用.在这种情况下,实现将省略的复制/移动操作的源和目标视为仅仅两种不同的方式来引用同一个对象[...]
- [...]
- 当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动
- [...]
显然,只有按值调用的版本符合此标准 - 在通过引用传递之后,参数毕竟被绑定到引用.除了可观察到的差异之外,这也意味着失去了优化机会.
| 归档时间: |
|
| 查看次数: |
1692 次 |
| 最近记录: |