简体   繁体   中英

C++: which is the appropriate constructor to be called: the constructor or the copy constructor?

The code

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;

}

prints "constructor" and that's fine. Now, when I uncomment the copy constructor, I get a compile time error:

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&}'

Which probably goes on to show that here the copy constructor will be called with a temporary ElisionTest(10) . And since you can't have a non-const reference to a temporary, making the argument of the copy constructor a const& should resolve the error.

But, if I modify the copy constructor to take const ElisionTest& instead of ElisionTest& , there's no error and the output is "constructor" again. Why didn't it print "copy constructor" ?

ElisionTest(ElisionTest& other);

A constructor with that signature allows the initialization of an ElisionTest instance through an lvalue. When you do this:

ElisionTest et = 10;

This will construct an instance of ElisionTest from a temporary. Your code is equivalent to:

ElisionTest et = ElisionTest(10);

This will call your constructor that takes a non-const reference and initialize et with that. But a non-const reference cannot be bound to a temporary. That's why we will need to add const to your copy-constructor so that it can support both lvalues and rvalues:

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

The reason you are seeing no output is because of something called copy-elision . The compiler can omit the call to the copy/move constructor. In GCC, you can use -fno-elide-constructors to turn off copy-elision.

It outputs "constructor" because it needs to convert from 10 to ElisionTest .

It didn't also print "copy constructor" because it got optimized away (copy elision). That's the only possible optimization that is allowed to alter the observable behavior of a program.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM