0

I am a newcomer to learning C++. I just tried to run the following code in vs code, but it reported an error

#include <iostream>
using namespace std;
class Entity
{
public:
    Entity()
    {
        cout << "default" << endl;
    }
    Entity(int x)
    {
        cout << x << endl;
    }
    Entity(Entity &e)
    {
        cout << "copy" << endl;
    }
    Entity &operator=(const Entity &e)
    {
        cout << "assignment" << endl;
        return *this;
    }
};
int main(void)
{
    Entity e = Entity(8);
}

The error is cannot bind non-const lvalue reference of type 'Entity&' to an rvalue of type 'Entity' Entity e = Entity(8);

I am searching for a long time on net. Some people say this is because compiler created temporary objects cannot be bound to non-const references, so adding const modifier will work.

Entity(const Entity &e)
{
    cout << "copy" << endl;
}

It seems that I am initializing an object with the copy constructor, otherwise the compiler should not report an error. But the fact is I'm using the parameterized constructor to do that. What puzzles me is why initialization in this way has something to do with the copy constructor?

weizao
  • 1
  • Consider a similar situation. `Entity e(8);` `Entity f = e;` Based on these two lines, which constructor do you expect to be used to construct `f`? – JaMiT Jul 28 '22 at 07:05
  • Using just the parameterized constructor is `Entity e(8);`. Your actual initialization is `Entity e(Entity(8));` – 273K Jul 28 '22 at 07:05
  • Which compiler do you use? `Entity e = Entity(8);` is syntactical sugar for `Entity e {8};` and does not need the (wrong) copy constructor. Your code does not create your error message: https://godbolt.org/z/xzsnsaPvc – mch Jul 28 '22 at 07:21
  • The compiler is MinGW-W64 gcc version 8.1.0 – weizao Jul 28 '22 at 07:46
  • @weizao From the dupe [Why C++ copy constructor must use const object?](https://stackoverflow.com/a/16956812/12002570), *"You couldn't create copies from temporary reference, because temporary objects are rvalue, and can't be bound to reference to non-const"*. Also refer to [Why is the copy-constructor argument const?](https://stackoverflow.com/questions/1602058/why-is-the-copy-constructor-argument-const) – Jason Jul 28 '22 at 09:09

1 Answers1

2

Entity(8); calls the constructor Entity(int x). Then you use that temporary to construct e. Because it is a temporary it cannot be passed to a method that has a non-const reference argument.

For further details I refer you to What are copy elision and return value optimization?. In short: The copy constructor must be available but the copy is then elided. Thanks to @MilesBudnek for the link.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • I see, thanks a lot. But I also have a question about why the explicit copy constructor will not be called after adding the const modifier. After I add the const modifier, the program does not output the "copy" string, only 8 – weizao Jul 28 '22 at 07:22
  • @weizao See ["What are copy elision and return value optimization?"](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization). Pre-C++17 a copy constructor was required to exist, even if the compiler ended up eliding the copy. C++17 changed the rules, and a copy constructor is no longer required in this situation. – Miles Budnek Jul 28 '22 at 07:25