首页 > 解决方案 > 返回 std::tuple 并移动语义/复制省略

问题描述

我有以下工厂功能:

auto factory() -> std::tuple<bool, std::vector<int>>
{
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);

    return { true, vec };
}

auto [b, vec] = factory();

在 return 语句中被vec认为是一个xvalueorprvalue并因此被移动或复制省略了?

我的猜测是否定的,因为编译器std::tuple在对 return 语句中的 进行列表初始化时,仍然不知道 vec 将被销毁。所以也许需要一个明确的 std::move :

auto factory() -> std::tuple<bool, std::vector<int>>
{
    ...
    return { true, std::move(vec) };
}

auto [b, vec] = factory();

真的有这个要求吗?

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

解决方案


在 return 语句中被vec认为是一个 xvalue 或 prvalue,因此被移动或复制省略了?

vec始终左值。即使在简单的情况下:

std::vector<int> factory() {
    std::vector<int> vec;
    return vec;
}

仍然返回一个左值。只是我们有特殊的规则说,在这种情况下,当我们返回自动对象的名称时,我们只是忽略副本(以及在复制省略不适用的情况下的另一个特殊规则,但我们仍然尝试从左值移动)。

但是那些特殊规则适用于return object;案件,它们并不适用于return {1, object};案件,无论它看起来多么相似。在您的代码中,这将进行复制,因为这就是您所要求的。如果你想移动,你必须这样做:

return {1, std::move(object)};

为了避免移动,您必须执行以下操作:

auto factory() -> std::tuple<bool, std::vector<int>>
{
    std::tuple<bool, std::vector<int>> t;

    auto& [b, vec] = t;
    b = true;
    vec.push_back(1);
    vec.push_back(2);
    return t;
}

推荐阅读