0
#include <iostream>

struct A
{
  // constructor 1
  A() { std::cout << "A() called" << std::endl; }

  // constructor 2
  A(const A&) { std::cout << "A(const A&) called" << std::endl; }
};

int main()
{
  // statement 1
  A x1;

  // statement 2
  A x2( A() );

  return 0;
}

I've compiled it with GCC 4.7, 5.1 and 8.1. I got the same results from C++98 to C++17.

Statement 1 creates an A variable that calls constructor 1.

Statement 2 declares a prototype of a function that takes a function pointer as its argument and returns a new A object:

A ( A (*)() )

I was expecting that statement 2 would create an A variable that calls constructor 2 since I am initializing with a temporary A object.

I'm not sure what I'm missing here. Can someone help me understand this unexpected situation?

AJ Tan
  • 193
  • 7
  • @Botje, I don't think so. There, they were already expecting that it is a function declaration. In my case, I didn't even know that a function can be declared that way and I was also not trying to declare ```x2``` as a function. Thanks anyways. – AJ Tan Oct 09 '20 at 14:30
  • Yes, that was exactly why I linked it. The problem you are facing is called ["most vexing parse"](https://stackoverflow.com/questions/14077608/what-is-the-purpose-of-the-most-vexing-parse) (your code is explicitly listed!) and it is solved by using brace-initialization `A x2{ A() };` or construction by assignment `A x2 = A();` – Botje Oct 09 '20 at 14:33
  • @Botje, your examples do declare objects but they don't use constructor 2. To be fair, it's not a straight up "no". They mentioned [this](https://eel.is/c++draft/dcl.ambig.res) which led me to understanding a little bit more about this "vexing parse". – AJ Tan Oct 10 '20 at 03:26
  • Did you read the second link I posted? Your exact problem line is the example they use. – Botje Oct 10 '20 at 06:43

1 Answers1

-1

In what is labelled statement 2 inside your code, you are creating a function pointer pointing to a new object, like you mention, but you don't instruct the program to actually store it, so x2, left as is in your snippet code, copies the pointer to a bygone temporary.

Storing the temporary A object from the function pointer will compile correctly:

// statement 2
A x2( *(new A()) );

[Since this is just for the sake of shedding light on this particular issue, we'll overlook that we are more than likely to create a memory leak if the line above finds its way in a real code base, because we have no means of control of the new A object that gets copied in x2.]

The output will be

A() called
A() called
A(const A&) called

Basically, yours was a good try, but unfortunately you cannot get away from creating another A() object, if you don't want to copy x2 from x1.

In order to save one constructor call, we could construct x2 from x1: using a function pointer, we first define it:

// statement 2
A (*fcnptr)(A);
A x2( (*fcnptr)(x1) );

which is the same as, more trivially

A x2(x1);

without using function pointers. The output:

A() called
A(const A&) called
Giogre
  • 1,444
  • 7
  • 19
  • Thank you. I've checked [here](https://eel.is/c++draft/dcl.ambig.res) and it seems that this is one of C++'s weird side that I may not ever wanna be. What a day. – AJ Tan Oct 09 '20 at 15:01
  • Nevermind, I understood you wanted to see the second constructor implemented. – Giogre Oct 09 '20 at 15:13