为什么这个移动构造函数如此贪婪?

Jos*_*uel 1 c++ copy-constructor move-constructor move-semantics c++11

我有以下代码:

#include <iostream>

class foo_class {
    std::string value;
public:
    foo_class(const foo_class& v) : value{v.value} {
        std::cout << "copy constructor" << std::endl;
    }

    foo_class(foo_class&& v) : value{std::move(v.value)} {
        std::cout << "move constructor" << std::endl;
    }

    ~foo_class() {
        std::cout << "destructor" << std::endl;
    }

    foo_class(std::string v) : value{std::move(v)} {
        std::cout << "type constructor" << std::endl;
    }
};

struct Data {
    foo_class a;
    foo_class b;
};

int main() {
    std::string c = "3";
    Data x{c,c+"3"};
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

重要的是,我使用GCC和Clang(分别为4.8.2和3.4)和标志-fno-elide-constructors进行编译,因此我们不会忽略复制/移动构造函数.

执行结果如下:

type constructor
move constructor
destructor
type constructor
move constructor
destructor
destructor
destructor
Run Code Online (Sandbox Code Playgroud)

这意味着复制构造函数根本没有被使用,即使它应该用于struct Data的构造函数的第一个参数.

接下来,如果我删除了复制构造函数,根据我的编译器,代码仍然合法,但在我的理解中应该是非法的,因为我在传递构造函数的第一个参数时没有转换为&&(使用std :: move)数据的.

我的问题很简单: 为什么会这样?我错过了什么吗?

WiS*_*GaN 6

因为foo_class构造的对象

Data x{c,c+"3"};
Run Code Online (Sandbox Code Playgroud)

都是临时的.所以他们调用移动构造函数而不是复制构造函数.

type constructor // 1. Construct a temporary foo_class object out of string "c" for a
move constructor // 2. Move the temporary object created above to x.a
destructor       // 3. Destruct the temporary foo_class object created in 1
type constructor // 4. Same as 1, but the object is for b, and the string "33"
move constructor // 5. Same as 2, moved to x.b
destructor       // 6. Destruct the temporary foo_class object created in 4
destructor       // 7. Destruct x.b
destructor       // 8. Destruct x.a
Run Code Online (Sandbox Code Playgroud)