【问题标题】:Implicit move the value contained in std::optional when return返回时隐式移动 std::optional 中包含的值
【发布时间】:2016-07-27 15:28:13
【问题描述】:

从 C++11 开始,我们有了移动语义。在下面的示例中,将使用移动构造函数(或复制省略),而不是 C++98 中的复制构造函数,无需任何额外的努力。

std::string f()
{
    std::string res;
    ...
    return res; // <- move is used here instead of copy
}

但是这个案子呢?

std::string f()
{
    std::optional<std::string> res;
    ...
    return *res; // <-- will the std::string value be moved??
}

还是必须写这样的东西?

std::string f()
{
    std::optional<std::string> res;
    ...
    return *std::move(res);
}

【问题讨论】:

  • 你的意思是后面两个例子返回string吗?
  • 是的。已编辑。谢谢!

标签: c++ move-semantics c++17


【解决方案1】:

。隐式移动的标准在[class.copy]:

当 [...],或者当 return 语句中的 表达式 是(可能 带括号的)id-expression 命名一个对象,该对象具有在主体中声明的自动存储持续时间或 parameter-declaration-clause 的最内层封闭函数或 lambda-expression,重载决议到 选择复制的构造函数首先执行,就好像对象是由右值指定的一样。

*res 不是 id-expression,因此该规则不适用。如果你想将底层字符串移出,你必须明确地这样做:

return std::move(*res);
return *std::move(res);
return std::move(res).value(); // equivalent and possibly more legible

这些规则旨在仅在绝对安全的情况下尝试更有效的选择。如果您要返回一个自动存储持续时间变量,那么移动它是完全安全的,因为没有其他东西会再次引用该变量。

但是,如果您要返回 *res,那么离开这里不一定安全。如果这给了你一个对某个外部对象的引用,它会比这个函数更长寿怎么办?我们将默默地从我们期望仍然有效的状态转移!在这种情况下,由您作为用户来声明您希望它移动。

【讨论】:

  • 你的意思是 *std::move(res)?
  • @VictorDyachenko 或者我猜你可以让函数返回一个optional&lt;string&gt;return res。那会动的。
  • 可能类似于return opt.move_value() 这样的界面对我来说会更直观
  • @VictorDyachenko std::move(*res)*std::move(res) 如果/当 std::optional 放松以使用引用类型时可能会有不同的语义。比较std::move(std::get&lt;0&gt;(x))std::get&lt;0&gt;(std::move(x)),其中x 是一个元组,以了解其含义。
  • @LucDanton 我们正在讨论 std::optional。 std::optional 有 std::optional::operator*() &&
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2020-06-06
  • 2022-12-22
  • 2018-02-23
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多