简体   繁体   English

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

[英]Return std::tuple and move semantics / copy elision

I have the following factory function:我有以下工厂功能:

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

In the return statement is vec considered an xvalue or prvalue and therefore moved or copy elided?在 return 语句中vec被视为xvalueprvalue并因此被移动或复制省略?

My guess is no, because the compiler, when list-initializing the std::tuple in the return statement, still doesn't know that vec is going to be destroyed.我的猜测是否定的,因为编译器在 return 语句中列表初始化std::tuple时,仍然不知道 vec 将被销毁。 So maybe an explicit std::move is required:所以也许需要一个显式的 std::move :

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

auto [b, vec] = factory();

Is it that really required?真的有这个要求吗?

In the return statement is vec considered an xvalue or prvalue and therefore moved or copy elided?在 return 语句中vec被视为 xvalue 或 prvalue 并因此被移动或复制省略?

vec is always an lvalue. vec始终是左值。 Even in the simple case:即使在简单的情况下:

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

That is still returning an lvalue.仍然是返回一个左值。 It's just that we have special rules that say that we just ignore the copy in this case when we're returning the name of an automatic object (and another special rule in the case that copy elision doesn't apply, but we still try to move from lvalues).只是我们有特殊的规则,在这种情况下,当我们返回一个自动对象的名称时,我们只是忽略副本(还有另一个特殊规则,在复制省略不适用的情况下,但我们仍然尝试从左值移动)。

But those special rules only apply to the return object;但那些特殊规则适用于return object; case, they don't apply to the return {1, object};情况下,它们不适用于return {1, object}; case, no matter how similar it might look.情况,无论它看起来多么相似。 In your code here, that would do a copy, because that's what you asked for.在您的代码中,这将进行复制,因为这是您所要求的。 If you want to do a move, you must do:如果你想做一个动作,你必须这样做:

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

And in order to avoid the move, you must do:为了避免移动,你必须这样做:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM