移动构造函数的问题

Tra*_*cer 0 c++ constructor move-semantics c++11

我正在测试一个移动构造函数并执行以下操作:

#include <iostream>
#include <string>
using namespace std;

class X{
    public:
        int* p;
        int size;
        X(){}
        X(int n) : size(n){
            p = new int[n];
            for(int i = 0; i < n; i++)
                p[i] = i;
            cout << "Constructor\n";
        }
        ~X(){
            delete[] p;
        }
        X(const X& r){
            cout << "Copy\n";

        }
        X(X&& r){
            p = r.p;
            size = r.size;
            r.p = NULL;
            r.size = 0;
            cout << "Move\n";
        }
};
int main() {
    X a(10); //constructor    
    X b(a); // copy
    X c(X(3)); //constructor, move
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我在输出中的预期是在注释中,但是在编译时(VS 2012)移动构造函数没有被调用?!但是,如果我向构造函数添加其他参数:

string name;
X(int n, string _name) : size(n), name(_name){
    p = new int[n];
    for(int i = 0; i < n; i++)
        p[i] = i;
    cout << "Constructor\n";
}
Run Code Online (Sandbox Code Playgroud)

然后

X a(10, "a"); //constructor
X b(a); // copy
X c(X(3, "pom")); //constructor, move
Run Code Online (Sandbox Code Playgroud)

我得到了预期的结果......我真的不明白为什么.

编辑:现在在GCC 4.7.2上测试,它在两种情况下都不调用Move构造函数,但C++ Builder XE5编译器调用两种情况下的Move构造函数.然而,VS仅在第二种情况下调用它(当使用额外的构造函数参数时).很有意思...

Pra*_*ian 7

编译器eliding移动建设并直接构建X(3)c,基本上是把你的初始化成

X c(3);
Run Code Online (Sandbox Code Playgroud)

使用gcc,您可以使用-fno-elide-constructors开关禁用它.添加后,原始示例的输出符合预期:

Constructor
Copy
Constructor
Move
Run Code Online (Sandbox Code Playgroud)

现场演示