为什么这个副本不能自动替换为移动?

时间:2013-11-21 00:45:52

标签: c++11 move-semantics

测试类:

#include <iostream>
#include <string>

struct inner
{
        std::string value;

        inner() : value("test") {
                std::cerr << "inner default construct\n";
        }
        inner(inner &&mv) : value(std::move(mv.value)) {
                std::cerr << "inner move construct\n";
        }
        inner(inner const &copy) : value(copy.value) {
                std::cerr << "inner copy construct\n";
        }
};

struct outer
{
        inner value;
        outer() {}
        outer(inner v)
                : value(v)
        {}
};

对移动语义的简单测试就是我所期望的:

inner mover(inner x)
{
        return x;
}
int main()
{
        inner i;
        auto q = mover(std::move(i));
        return 0;
}

......输出:

  

内部默认构造

     

内部移动构造

     

内部移动构造

但这个主要做了我没想到的事情:

int main()
{
        inner i;
        outer o(std::move(i));
        return 0;
}
  

内部默认构造

     

内部移动构造

     

内部复制构造

我期待副本成为另一个举动,因为它是第一个主要的。为什么在第一种情况下使用移动优化而在第二种情况下不可用?

我意识到我可以在outer(inner v)构造函数中显式调用std :: move ......但为什么需要这样做?为什么编译器不能进行隐式移动?

2 个答案:

答案 0 :(得分:3)

您需要在初始化列表中说: value(std::move(v))

答案 1 :(得分:2)

我不是C ++ 11 rvalue sematics的专家,但outer没有接受inner rvalue引用的构造函数,因此编译器别无选择,只能生成{{1复制,因为inner构造函数的输入参数是左值,因此在初始化outer成员时必须调用inner复制构造函数而不是移动构造函数。

您在outer::v示例中未获得副本的原因可能是由Return Value Optimization引起的,如果输入mover()实例可以直接移动,则无需任何副本目标inner变量,从而调用q移动构造函数而不是复制构造函数。