2

I am trying to figure out how to better organize my code, so I've made a simple example representing the issue:

Given ClassA and ClassB:

class ClassA
{
public:

    ClassA() { cout << "ClassA ctor\n"; }

    ClassA(const ClassA &other) { cout << "ClassA copy ctor\n"; }

    ClassA& operator=(ClassA other) {
        cout << "ClassA assignment\n";
        return *this;
    }

    ~ClassA() { cout << "ClassA destructor\n"; }
};

class ClassB {
    ClassA mA;
public:

    ClassB(ClassA a) : mA(a) {
        cout << "ClassB ctor\n";
    }

    ~ClassB() { cout << "ClassB destructor\n"; }
};

Can somebody explain if there is a way why this code works:

void test3(ClassA pA) { cout << "Test3\n"; }
...
test3(ClassA());

producing the output:

ClassA ctor

Test3

ClassA destructor

While this code doesn't:

ClassB b(ClassA());

ClassB constructor is not even being executed in this case (although no error is thrown either).

Is there a way to avoid copy ctor when passing argument by value to a ctor?

Community
  • 1
  • 1
Chebz
  • 1,375
  • 3
  • 14
  • 27
  • `ClassB` constructor takes a non-const reference as a parameter. `ClassA()` is a temporary. A temporary cannot bind to non-const reference. – Igor Tandetnik Jul 04 '15 at 23:07
  • @IgorTandetnik `ClassB` takes an instance of `ClassA` by value not by reference. – Captain Obvlious Jul 04 '15 at 23:08
  • @CaptainObvious Well, it does now. It didn't a minute ago. – Igor Tandetnik Jul 04 '15 at 23:08
  • @Igor sorry I've made mistake in post, it is by value in code. – Chebz Jul 04 '15 at 23:11
  • In `ClassB(ClassA());`, if it weren't for copy elision, you'd see a copy constructor called *twice*: once to copy `ClassA()` temporary to function parameter, and again to copy this parameter to `mA` member variable. The first copy is elided, the same way it is in `test3` call. But there ain't no way to elide the second copy, the `mA(a)` part. – Igor Tandetnik Jul 04 '15 at 23:13
  • @IgorTandetnik no it doesnt even call B's constructor (no output printed in console). If I change it to 'ClassA a; ClassB b(a);' then it works, with copy ctor being called once. – Chebz Jul 04 '15 at 23:16
  • 1
    Ah. Most vexing parse. `ClassB b(ClassA());` declares a function named `b` returning `ClassB` and taking a parameter of type "function with no parameters returning `ClassA`" - not an object of type `ClassB`. As there's no object, there's nothing to construct. – Igor Tandetnik Jul 04 '15 at 23:18
  • There is no copy elision happening, it's just https://en.wikipedia.org/wiki/Most_vexing_parse As for: _"Is there a way to avoid copy ctor when passing argument by value to a ctor?"_ -- there is no copy constructor call, what are you talking about?! It's already elided! You can't make it do as little as `ClassB b(ClassA());` because that does **nothing** but that's probably not what you want. – Jonathan Wakely Jul 04 '15 at 23:22

0 Answers0