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

C++ 返回时隐式移动std::optional中包含的值,c++,move-semantics,c++17,C++,Move Semantics,C++17,从C++11开始,我们就有了移动语义。在下面的示例中,将使用move构造函数或copy-elision,而不是C++98中的copy构造函数,无需任何额外的工作 std::string f() { std::string res; ... return res; // <- move is used here instead of copy } 但是这个案子呢 std::string f() { std::optional<std::string&g

从C++11开始,我们就有了移动语义。在下面的示例中,将使用move构造函数或copy-elision,而不是C++98中的copy构造函数,无需任何额外的工作

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]中:

当[…]或返回语句中的表达式可能是 括号中的id表达式,用于命名在最内层封闭函数或lambda表达式的body或parameter declaration子句中声明了自动存储持续时间的对象,重载解析为 选择首先执行复制的构造函数,就像对象由右值指定一样

*res不是id表达式,因此此规则不适用。如果要将基础字符串移出,必须显式执行:

return std::move(*res);
return *std::move(res);
return std::move(res).value(); // equivalent and possibly more legible
这些规则旨在只有在绝对安全的情况下才尝试更有效的选择。如果您要返回一个自动存储持续时间变量,那么移动它是完全安全的,因为没有其他变量会再次引用该变量

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

否。隐式移动的条件在[class.copy]中:

当[…]或返回语句中的表达式可能是 括号中的id表达式,用于命名在最内层封闭函数或lambda表达式的body或parameter declaration子句中声明了自动存储持续时间的对象,重载解析为 选择首先执行复制的构造函数,就像对象由右值指定一样

*res不是id表达式,因此此规则不适用。如果要将基础字符串移出,必须显式执行:

return std::move(*res);
return *std::move(res);
return std::move(res).value(); // equivalent and possibly more legible
这些规则旨在只有在绝对安全的情况下才尝试更有效的选择。如果您要返回一个自动存储持续时间变量,那么移动它是完全安全的,因为没有其他变量会再次引用该变量


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

你是说后面的两个例子返回字符串吗?是的。编辑。谢谢你是说后面的两个例子返回字符串吗?是的。编辑。谢谢你是说*std::moveres?@VictorDyachenko还是我猜你可以让函数返回一个可选值,然后返回res。它会移动。可能类似于返回opt。move_值会更直观一些,至于me@VictorDyachenko如果/当std::optional放松以使用引用类型时,std::move*res和*std::moveres可能具有不同的语义。比较std::movestd::getx和std::getstd::movex,其中x是一个元组,以了解哪个表示哪个。@LucDanton我们正在讨论std::optional。std::optional有std::optional::operator*&&你是说*std::moveres?@VictorDyachenko还是我猜你可以让函数返回一个optional并返回将要移动的res。可能类似于return opt.move_值,界面会更直观一些,至于me@VictorDyachenko如果/当std::optional放松以使用引用类型时,std::move*res和*std::moveres可能具有不同的语义。比较std::movestd::getx和std::getstd::movex,其中x是一个元组,以了解哪个表示哪个。@LucDanton我们正在讨论std::optional。std::optional具有std::optional::operator*&&