临时对象的子对象是否保证在返回时被移动?

xml*_*lmx 11 c++ standards move-semantics c++11

#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);
}
Run Code Online (Sandbox Code Playgroud)

我知道:如果我只是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();
}
Run Code Online (Sandbox Code Playgroud)

gcc 6.2和clang 3.8输出相同:

建造

拷贝构造

自毁

自毁

T.C*_*.C. 3

“隐式移动”规则的最简洁的表述位于当前工作论文的[class.copy.elision]/3中:

在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

  • 如果return 语句 ([stmt.return]) 中的表达式是一个(可能带括号的) id 表达式,该 id 表达式命名具有在最内层封闭函数或lambda表达式的主体或 参数声明子句中声明的自动存储持续时间的对象, 或者

  • [...]

首先执行重载决策来选择副本的构造函数,就好像该对象是由右值指定的一样。如果第一次重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的右值引用(可能是 cv 限定的),则再次执行重载决策,并将该对象视为左值。

也不b.acoll[0]id -expression。因此,并没有隐性的举动。如果你想要移动,你必须明确地这样做。