【问题标题】:Is the sub-object of a temporary object guaranteed to be moved on return?临时对象的子对象是否保证在返回时被移动?
【发布时间】:2017-01-07 08:18:18
【问题描述】:
#include <string>
#include <vector>

using namespace std;

auto f()
{
    vector<string> coll{ "hello" };

    //
    // Must I use move(coll[0]) ?
    //
    return coll[0]; 
}

int main()
{
    auto s = f();
    DoSomething(s);
}

我知道:如果我只是return coll;,那么coll 肯定会在返回时被移动。

但是,我不确定:coll[0] 是否也保证在返回时被移动?

更新:

#include <iostream>

struct A
{
    A() { std::cout << "constructed\n"; }
    A(const A&) { std::cout << "copy-constructed\n"; }
    A(A&&) { std::cout << "move-constructed\n"; }
    ~A() { std::cout << "destructed\n"; }
};

struct B
{
    A a;
};

A f()
{
    B b;
    return b.a;
}

int main()
{
    f();
}

gcc 6.2 和 clang 3.8 输出相同:

构造

复制构造

破坏

破坏

【问题讨论】:

  • "那么coll 保证在返回时被移动。"不,不是。副本可能会被省略,在这种情况下,没有移动。
  • 你没有使用 f() 的返回值,有什么要移动的?
  • 并且可以移动左值的条件与复制省略密切相关(请参阅我的答案。)

标签: c++ c++11 standards move-semantics


【解决方案1】:

当返回一个本地对象时,既不会使用复制也不会使用移动,而是使用复制省略,这比移动更受欢迎。这是因为控制复制省略和移动本地对象的规则是相同的。当通过显式使用std::move 来强制移动时,如

template<typename T>
std::string make_string(T const& x)
{
  std::ostringstream str;
  str << x
  return std::move(str.str());    // not recommended
}

最新版本的 clang 发出警告

移动临时对象可防止复制省略 [-Wpessimizing-move]

但是,您的代码中的情况不同。与返回对象(std::string)的std::ostringstream::str() 不同,std::vector&lt;&gt;::operator[] 返回必须转换为对象的引用(因为auto 删除了引用)。在这种情况下,复制省略是不可能的(因为实际对象是另一个具有非平凡析构函数的对象的一部分)并且应该使用std::move() 来避免复制。

这些注意事项建议在不确定时使用 std::move(),但如果 clang 发出高于警告的问题,请将其删除。

【讨论】:

  • 没有。在我的原始示例中,gcc 6.2 和 clang 3.8 都没有复制省略。查看我的更新。
【解决方案2】:

“隐式移动”规则的最简洁表述在当前工作文件的[class.copy.elision]/3

在以下复制初始化上下文中,移动操作可能 用于代替复制操作:

  • 如果 return 语句 ([stmt.return]) 中的 expression 是一个(可能带括号的)id-expression,它用 在正文中声明的自动存储持续时间或 parameter-declaration-clause 最里面的封闭函数或 lambda-expression,或

  • [...]

为拷贝选择构造函数的重载分辨率是第一个 就像对象由右值指定一样执行。如果第一个 重载决议失败或未执行,或者如果 所选构造函数的第一个参数不是右值引用 对于对象的类型(可能是 cv 限定的),重载决议是 再次执行,将对象视为左值。

b.acoll[0] 都不是 id 表达式。因此,没有隐含的举动。如果你想搬家,你必须明确地去做。

【讨论】:

    猜你喜欢
    • 2012-06-20
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    • 2013-06-13
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多