c++ - 我应该通过右值引用返回一个右值引用参数吗?

标签 c++ c++11 move

我有一个函数可以就地修改 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 问题(例如 herehere),并得出结论认为这是不好的做法。

根据我的阅读,似乎共识是,由于返回值右值,加上考虑到 RVO,仅按值返回将同样有效:

std::string transform(std::string&& input)
{
    return transform(input); // calls the lvalue reference version
}

但是,我还了解到返回函数参数会阻止 RVO 优化(例如 herehere)

这让我相信会从 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)

  1. 参数不能是临时的(这正是右值引用所代表的),或者
  2. 返回值不会保留在调用者上下文中的下一个分号之后(当临时对象被销毁时)。

如果调用者传递一个临时值并尝试保存结果,他们会得到一个悬空引用。

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/

相关文章:

c++ - Boost线程析构函数 undefined symbol

c++ - GLSL 编译器错误 error C0000 : syntax error, unexpected identifier, expecting "::"at token <var>

c++ - 为什么我的词法分析器无法识别引号 ""

c++ - 将输入发送到后台窗口

c++ - boost 或 STL 是否有用于比较两个 char 值的谓词?

c++ - 使用 foreach 循环连续迭代两个结构的简单方法

c++ - 通过 move 派生类来构造基类

c++ - 我可以从基于范围的 for 中 move 元素吗?

c++ - 使用 C++,如何将迭代器实现到我自己的容器类中,以便我可以使用类似 std::sort() 的东西

sql - 在 PostgreSQL 中将数据从一列 move 到另一列