我有一个函数可以就地修改 std::string&
左值引用,返回对输入参数的引用:
std::string& transform(std::string& input)
{
// transform the input string
...
return input;
}
我有一个辅助函数,它允许对右值引用执行相同的内联转换:
std::string&& transform(std::string&& input)
{
return std::move(transform(input)); // calls the lvalue reference version
}
注意它返回一个右值引用。
我已经阅读了几个关于返回右值引用的 SO 问题(例如 here 和 here),并得出结论认为这是不好的做法。
根据我的阅读,似乎共识是,由于返回值是右值,加上考虑到 RVO,仅按值返回将同样有效:
std::string transform(std::string&& input)
{
return transform(input); // calls the lvalue reference version
}
但是,我还了解到返回函数参数会阻止 RVO 优化(例如 here 和 here)
这让我相信会从 transform(...)
的左值引用版本的 std::string&
返回值复制到 >std::string
返回值。
对吗?
保留我的 std::string&& transform(...)
版本更好吗?
最佳答案
没有正确答案,但按值返回更安全。
I have read several questions on SO relating to returning rvalue references, and have come to the conclusion that this is bad practice.
返回对参数的引用会向调用者强加一个契约(Contract)
- 参数不能是临时的(这正是右值引用所代表的),或者
- 返回值不会保留在调用者上下文中的下一个分号之后(当临时对象被销毁时)。
如果调用者传递一个临时值并尝试保存结果,他们会得到一个悬空引用。
From what I have read, it seems the consensus is that since return values are rvalues, plus taking into account the RVO, just returning by value would be as efficient:
按值返回添加了 move 构造操作。这样做的成本通常与对象的大小成正比。而按引用返回只需要机器确保一个地址在寄存器中,按值返回需要将参数std::string
中的一对指针归零。并将它们的值放入新的 std::string
被退回。
它很便宜,但不为零。
标准库目前采取的方向有点令人惊讶的是,快速且不安全并返回引用。 (我知道实际执行此操作的唯一函数是 std::get
来自 <tuple>
。)碰巧,我提出了 a proposal致 C++ 核心语言委员会解决此问题,a revision正在进行中,就在今天,我开始调查实现。但这很复杂,而且不确定。
std::string transform(std::string&& input) { return transform(input); // calls the lvalue reference version }
编译器不会生成 move
这里。如果 input
根本不是引用,你做了return input;
它会,但它没有理由相信 transform
将返回 input
仅仅因为它是一个参数,并且无论如何它都不会从右值引用类型中推断出所有权。 (参见 C++14 §12.8/31-32。)
你需要做的:
return std::move( transform( input ) );
或等效
transform( input );
return std::move( input );
关于c++ - 我应该通过右值引用返回一个右值引用参数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30094067/