2

I have a question about copy constructors, suppose a class A that contains an int, with default constructor, copy constructor (?), and constructor that receives an int

class A {
  int value;
public:
  A(): value(0) {}                  // Default
  A(A& copy): value(copy.value) {}  // Copy (?)
  A(const int n): value(n) {}       // Receives an int for 'value'

  int get_value() { return value; } // Return value
};

And a class that contains an A pointer, named BoxForA :

class BoxForA {
  A *obj;
public:
  BoxForA(): obj(nullptr) {}
  BoxForA(const int a) { obj = new A(a); }

  A popf(){ return *obj; }  // Returns the content of obj_A (an A element)
};

And the main (that will print three 3):

int main() {
  A a(3);
  A b = a;  // Calling copy constructor for b (this works with non-const parameter)

  BoxForA box1(3);
  A c = box1.popf();  // Calling copy constructor for c (this doesn't work with non-const parameter)

  cout << "a = " << a.get_value() << endl;
  cout << "b = " << b.get_value() << endl;
  cout << "c = " << c.get_value() << endl;
  return 0;
}

When I compiled this, the compiler gave me this error:

error: invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’
   A c = box1.popf();
                  ^

Just with that, I suppose that my copy constructor need const parameter, instead of non-const, so editing my copy constructor like this:

A(const A& obj): value(obj.value) {}

My program now compiles without errors and show this output:

a = 3
b = 3
c = 3

Nice! I found the solution :D .... Nope, because I don't know why it works.

Can you tell me why happens that? Why the copy constructor seems to have const parameter?

  • `box1.popf()` returns a temporary - it can only be 'bound' to a const reference. – Michael Burr Nov 11 '16 at 21:59
  • if you say must it be constant then NO. if you ask should it then yes. `cpy ctor` takes a reference to an object of the same class and copies its values to the new one `being created` and as long as it doesn't change the `rhs` values then the law of thumb we pass to it a const reference – Raindrop7 Nov 11 '16 at 22:14

1 Answers1

5

When you write

A c = box1.popf();

It calls the copy constructor, as you know:

A c(box1.popf()); // copy constructor

Now, what does popf return? It returns an A, a prvalue (basically an rvalue - there is a difference in C++11). But wait, the copy constructor takes a &, which only binds to lvalues, and so your code doesn't compile.

But when you add const, the signature is now const&, which accepts rvalues and lvalues, and the code compiles.

You get exactly the same problem if you write:

int& a = 1; // 1 is a prvalue, but a only accepts lvalues
Rakete1111
  • 47,013
  • 16
  • 123
  • 162