C ++:这是要调用的适当构造函数:构造函数还是复制构造函数?

时间:2013-06-16 18:53:55

标签: c++ constructor type-conversion copy-constructor copy-elision

代码

class ElisionTest
{
public:
    int n;
    // ElisionTest(ElisionTest& other): n(other.n) {cout<<"copy constructor"<<endl;}
    ElisionTest(int n): n(n) {cout<<"constructor"<<endl;}
};

int main(int argc, char const *argv[])
{
    ElisionTest et = 10;

}

打印"constructor",这很好。现在,当我取消注释复制构造函数时,我得到一个编译时错误:

cpp_test.cpp: In function 'int main(int, const char**)':
cpp_test.cpp:140:19: error: no matching function for call to 'ElisionTest::ElisionTest(ElisionTest)'
cpp_test.cpp:140:19: note: candidates are:
cpp_test.cpp:135:2: note: ElisionTest::ElisionTest(int)
cpp_test.cpp:135:2: note:   no known conversion for argument 1 from 'ElisionTest' to 'int'
cpp_test.cpp:134:2: note: ElisionTest::ElisionTest(ElisionTest&)
cpp_test.cpp:134:2: note:   no known conversion for argument 1 from 'ElisionTest' to 'ElisionTest& {aka ElisionTest&}'

这可能会继续表明复制构造函数将使用临时ElisionTest(10)进行调用。并且由于您不能对临时引用非const引用,因此使const&的复制构造函数的参数可以解决错误。

但是,如果我修改了复制构造函数以取const ElisionTest&而不是ElisionTest&,则没有错误,输出再次为"constructor"。为什么不打印"copy constructor"

2 个答案:

答案 0 :(得分:2)

ElisionTest(ElisionTest& other);

具有该签名的构造函数允许通过左值初始化ElisionTest实例。当你这样做时:

ElisionTest et = 10;

这将从临时构造ElisionTest的实例。您的代码相当于:

ElisionTest et = ElisionTest(10);

这将调用构造函数,该构造函数接受非const引用并使用它初始化et。但是非const引用不能绑定到临时引用。这就是为什么我们需要将const添加到你的拷贝构造函数中,以便它可以同时支持左值和右值:

ElisionTest(ElisionTest const& other);
//                      ^^^^^

您看不到输出的原因是因为copy-elision。编译器可以省略对复制/移动构造函数的调用。在GCC中,您可以使用-fno-elide-constructors关闭copy-elision。

答案 1 :(得分:1)

它会输出"constructor",因为它需要从10转换为ElisionTest

它也没有打印"copy constructor",因为它已被优化(复制省略)。这是允许改变程序的可观察行为的唯一可能的优化。