2

Below is the snippet aimed to test the constructors. It was run in VS 2015.

In my opinion, "B b(B())" has the same function as "B b = B()", however, my code seems to say that they behave different.

I know there's copy elision by compiler optimization, but I think the default constructor should be called at least when execute "B b(B())". Can anyone help point out where my misunderstood is?

class B
{
public:
    B() {
        ++i;
        x = new int[100];
        cout << "default constructor!"<<" "<<i << endl;
        cout << "x address:" << x << endl << "--------" << endl;
    }
    B(const B &b)  //copy constructor
    {   
        ++i;
        cout << "Copy constructor & called " << i<< endl 
            << "--------" << endl;
    }
    B(B &&b)//move constructor
    {
        x = b.x;    
        ++i;
        b.x = nullptr;
        cout << "Copy constructor && called" << i << endl 
            <<"x address:"<< x << endl << "--------" << endl;

    }
    void print()
    {
        cout << "b address:" << x << endl << "--------" << endl;
    }
private:
    static int i;
    int *x;
};
int B::i = 0;


int main()
{
    B b1; //default constructor
    b1.print();
    B b2 = B(); //default constructor only
    b2.print();
    B b3(B());  //????nothing called... why???
    B b4 = b2; //copy constructor
    B b5 = move(b2); //move constructor
    b2.print();

    return 0;
}

enter image description here

M.M
  • 138,810
  • 21
  • 208
  • 365
Shirley Feng
  • 143
  • 1
  • 10

1 Answers1

4

Note that B b(B()) is a function declaration, not a variable definition at all, then no constructor would be called.

According to Most vexing parse, B b(B()) is a function declaration, for a function named b which returns an object of type B and has a single (unnamed) parameter which is a pointer to function returning type B and taking no parameter.

You can solve it by using braces (list initlization (since C++11)), like

B b1( B{} );
B b2{ B() };
B b3{ B{} };  // preferable from C++11
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Nice catch! @Shirley Feng, according to the wiki article, you can get the expected behavior by adding parenthesis around your inner ctor call. Example: `B b3( (B()) );` – souldzin Oct 18 '16 at 02:55
  • Thank you for the share!! It saves me XD – Shirley Feng Oct 18 '16 at 02:57
  • Just wonder, shouldn't it be better to keep using one convention for initialization? i.e. `B b{ B{} };` instead – Adrian Shum Oct 18 '16 at 03:07
  • 1
    @AdrianShum You're right. I just want to point out that only using one pair of braces would solve the ambiguity here. – songyuanyao Oct 18 '16 at 03:10
  • @ShirleyFeng Yes! It's a really important C++11 feature. – songyuanyao Oct 18 '16 at 03:31
  • @songyuanyao Hi, I have a new doubt about the call of copy constructor regarding anonymous object. B b1{ move(B{}) }; can call the move constructor. but is there anyway that we can trigger the copy constructor when initialize an object with another anonymous one? Thanks! – Shirley Feng Oct 18 '16 at 05:39
  • @ShirleyFeng What do you want to achieve? You can write a function similar with `std::move`, like `B foo(const B& b) { return b; }`, then `B b{ foo(B{}) };`. – songyuanyao Oct 18 '16 at 06:34