-1

I was looking at this code:

A foo() {
    cout << "foo" << endl;
    A a;
    return a;
}
void bar(const A& a) {
    cout << "bar" << endl;
}
int main() {
        A a;
        bar(a);
        bar(foo());
}

and was trying to understand why the c++ language is so anxious for me to put the const infront of A& a when i pass bar a temporary object, as i do in bar(foo());.
After all, if it's possible to access the temporary object, than why is it so bad for me change it as well?
Sometimes i will pass an lValue and bar() will change it as needed, and sometimes i will send an rValue and bar() will waste a little resources to change it, and then, the temporary object will be deleted. what's the big problem? some wasted clock cycles? i can live with that! right?
why should anyone care what i do with my temporary object? they are going to be deleted soon, their faith suppose to be no one's business..

1 Answers1

0

the answer is foo()!
It's TOO EASY TO FORGET or be confused about when i am passing an lValue and when i am passing an rValue in main().
Holding a reference to a real object and changing it (writing to it) is the desired functionaliy!
And holding a reference to a temporary object and changing it is - in first sight - harmless! right? what's the worst that can happen from writing to a temporary object? it will be gone soon anyway..
This is of course not true.
If c++ allowed me to pass a non-const temporary object to bar() than it would be MY RESPONSIBILITY to ALWAYS make sure that i am never mistakenly passing a temporary object to bar() when I need to pass an lValue!
This is a source for bugs that are hard to detect. so it's better to save the programmer from himself, and not letting him the ability of writing to temporary objects, not because we want to save the temporary objects, but because we want to save the programmer early in COMPILE TIME about his logical mistake of passing an rValue, when he actually wanted to change an lValue.
For example, consider this code:

A foo() {
    cout << "foo" << endl;
    A a;
    return a;
}
A& dim(A& a) {
    return a;
}
void bar( A& a) {
    cout << "bar" << endl;
}
int main() {
    A a;
    bar(dim(a));
}

Here we don't need to use const since bar() is now getting a reference to an lValue from dim().
How can a human keep track to when he is passing a reference to an lValue, and when he is passing a reference to an rValue? HE CAN'T. If c++ allowed a method to accept a ref to rValue, it would become a real hard error to debug, and would not benefit the developer any usage. ever.
I believe that by now if you are reading this, you are hopefully feeling like me - i don't want c++ to allow me to write to a temporary object! It's useless! and it can complicate my life, forcing me to check myself if a certain method returns a reference to an lValue or an rValue.
And this is why const is important here, it creates a distinction between two versions of the same function: the one that can change the object, and the one that can't

Look at this code:

class A {
public:
    A() { cout << "A ctor" << endl; }
    A(const A& o){ cout << "A cctor" << endl; }
    ~A() { cout << "A Dtor" << endl; }
};
A foo() {
    cout << "foo" << endl;
    A a;
    return a;
}
A& dim(A& a) {
    return a;
}
void bar( A& a) {
    cout << "bar" << endl;
}
void bar(const A& a) {
    cout << "const bar" << endl;
}
int main() {
    A a;
    bar(dim(a));
    bar(foo());
}

Here we have two almost identical methods both named bar and both receive a ref to instance of A.
The only difference is that one of the can change the reference and one of them can't.
The call bar(dim(a)) will invoke void bar( A& a)
Where bar(foo()) will invoke bar(const A& a)
So for the last time: if c++ allowed me to send rValue to a method that can change that rValue, and if i made the mistake of using this option - it would be a logical error for sure! since there is no reason to change an rValue.
Logical errors are harder to debug than compilation errors.