返回时隐式移动std::optional中包含的值

Implicit move the value contained in std::optional when return

本文关键字:optional 包含 std 移动 返回      更新时间:2023-10-16

自从C++11以来,我们就有了移动语义。在下面的例子中,将使用move构造函数(或复制省略),而不是像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);
}

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

当[…],或者当return语句中的表达式是(可能带括号)id表达式,该表达式命名具有在最内部封闭函数的正文或参数声明子句中声明的自动存储持续时间的对象,或lambda表达式

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

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

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

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