返回std :: tuple并移动语义/复制elision

问题描述 投票:9回答:1

我有以下工厂功能:

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();

在返回声明中,vec被认为是xvalueprvalue,因此移动或复制被删除?

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

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

auto [b, vec] = factory();

这真的需要吗?

c++ c++17 move-semantics
1个回答
12
投票

在return语句中,vec被认为是xvalue或prvalue,因此移动或复制被删除了?

vec总是一个左右。即使在简单的情况下:

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

那仍然是一个左值。只是我们有special rules说我们只是在这种情况下忽略副本,当我们返回一个自动对象的名称时(另一个special rule在副本省略不适用的情况下,但我们仍然试图从左值)。

但这些特殊规则仅适用于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;
}
© www.soinside.com 2019 - 2024. All rights reserved.