4

Lets say I have class A:

class A {
    int i;
public:
    A(){};
    A(int i){this->i=i;};
};

And a simple test function:

void test(const A &a){...}

Now, if I do:

int main()
{
    test(2);
} 

It compiles and it will call the A(int i) constructor. But when I change the argument to be non-const: void test(A &a) I get a compilation error.
What is the difference between those cases, why the first one is allowed and the second not, and what actually happens in the initialization of the first case?

A. Sarid
  • 3,916
  • 2
  • 31
  • 56
  • see http://stackoverflow.com/questions/8293426/error-invalid-initialization-of-non-const-reference-of-type-int-from-an-rval – twin Jun 25 '16 at 10:37
  • I guess you should look at [this](http://stackoverflow.com/questions/3895647/why-const-for-implicit-conversion) too. – meJustAndrew Jun 25 '16 at 10:38

3 Answers3

1

The difference between the two cases is that C++ compiler is allowed to create temporary objects to be passed to functions accepting a const references, but functions accepting non-const references must be provided with actual objects.

When you call test(2) what actually happens is this:

A hidden(2);
test(hidden);

The compiler creates hidden object, initializes it with 2, and passes the result to test. Since test is guaranteed to not modify A, this is fine.

When test does not provide such guarantee: imagine test that sets a new value:

void test(A& a) {
    a.i++; // let's pretend "i" is public
}

If you call test with an actual object, i.e. A a(3); test(a); you can harvest the result of the update from a after test return. Calling test(2), on the other hand, gives you no way to access the result of an update. This indicates a potential error in the logic, so the compiler treats it as an error.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

what actually happens in the initialization of the first case?

In the 1st case, a temporary A will be constructed implicitly by A::A(int) and then bound to the lvalue reference to const. The effect of test(2); is same as test(A(2));.

Temporary can't be bound to lvalue reference to non-const, that's why the 2nd case failed.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
0

This is an interesting case. using const you can bind a reference to an rvalue. A more simpler example is below.

int get_num()
{
    return 2;
}

int main(){
    int& p = get_num(); // This is a compiler error. Can't create a non-const reference to an rvalue
    const int& q = get_num(); // this will work. Can create const reference to an rvalue
}

This is part of the c++ standard.

cplusplusrat
  • 1,435
  • 12
  • 27