3

Possible Duplicates:
constructor invocation mechanism
Why is it an error to use an empty set of brackets to call a constructor with no arguments?

Why can this code elide all copies of A?

#include <iostream>

class A
{
public:
  A() {}
  A(const A&) { std::cout << "Copy" << std::endl; }
};

class B
{
public:
  B(const A& a_) : a(a_) {}
private:
  A a;
};

int main()
{
  B b(A());
}

This code apparently makes no copies of A, and outputs nothing under gcc 3.4 at ideone.

Community
  • 1
  • 1
Clinton
  • 22,361
  • 15
  • 67
  • 163

3 Answers3

9

The problem is not copy elision, but the meaning of the declaration:

B b(A());
// To get it working the way you expect [1]
B b = B(A());
// Or the slightly more obtuse.
B b((A()));

To the compiler is a function declaration. Google / search SO for the most-vexing-parse. More in the C++ FAQ lite including workarounds.


[1]: This is not exactly the same, as this requires an implicit conversion from A to B. If B was defined as:

class B {
  A a;
public:
  explicit B(const A& a_) : a(a_) {}
};

Then this would not be an alternative.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
7
B b(A());

You think this declares a variable? No.

It declares a function b whose return type is B and accepts a parameter of type A (*)() .

See this topic:


So if you want to declare a variable, put an extra braces around A() as:

B b((A())); //it declares an object
Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Alternatively, instead of adding parenthesis use an equals sign: `B b = A();` is *almost* equivalent to `B b(( A() ));` (difference being present only if the `B(A)` constructor was explicit) – David Rodríguez - dribeas Jul 14 '11 at 08:30
  • @David, why *almost*? Both are exactly same. I think `explicit` is not standard C++. – iammilind Jul 14 '11 at 08:44
  • @iammilind: You can mark a constructor as explicit, and then it will not be used by implicit conversions. If `B` was declared as `struct B { explicit B( A const & ) {} };` then `B b(( A() ));` would work (code explicitly requests that constructor) while `B b = A();` would not because there is no implicit conversion from `A` to `B`. `B b = A();` is processed by the compiler as `B b = B(( A() ));` where the left hand side conversion is *implicit*. – David Rodríguez - dribeas Jul 14 '11 at 09:17
1

Use:

B b((A()));

your line is a function declaration. Unfortunately C allowed function declarations inside functions (which BTW seem pretty useless to me), so for backward compatibility reasons C++ allows this to. You can enforce variable definition with extra parentheses.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176