class MyClass
{
public:
MyClass() { std::cout << "constructor\n"; }
~MyClass() { std::cout << "destructor\n"; }
const MyClass& print(int i) const
{
std::cout << i << std::endl;
return *this;
}
};
//---------------------------------------------------------
//---------------------------------------------------------
int main()
{
std::cout << "Before\n";
const MyClass& obj = MyClass(); //*
std::cout << "After\n";
obj.print(2);
}
//---------------------------------------------------------
MyClass getMyClass() { return MyClass(); }
Now if we change the line marked with //* to this:
const MyClass& obj = getMyClass(); //*
the result will still be the same. So clearly the lifetime of the return
value of a function is extended by the reference.
Now comes the puzzling part, and my actual question. Suppose that we
change the line marked with //* to this:
const MyClass& obj = MyClass().print(1); //*
Suddenly the output changes:
Before
constructor
1
destructor
After
2
Imagine:
// using your 'MyClass' class
MyClass const& pass(MyClass const& arg) { return arg; }
MyClass const& bad = pass(pass(pass(pass(MyClass()))));
Some might think that it is the same reference initialised by binding
it to the temporary being passed in and out of the 'pass' function and
eventually put into the 'bad' reference. But it *isn't*! The
argument of the 'pass' function and its return value are *different
references*. The return value is initialised from the argument
initialised from the temporary. So, if the rule was only about
binding a ref to a temporary, the temporary would only lives as long
as the argument of the very first 'pass' function (the inner-most).
The "until the full expression is evaluated" requirement would
override that in this case, so you should see the temporary report its
destruction right after the last 'pass' returns, just before 'bad' is
initialised.
> How does it
make even sense that a reference can be created to an object which is
destroyed immediately after the reference is created?
The same way that a pointer can be created to an object that has
already been destroyed:
Object* foo(Object *p) {
delete p;
return p;
}
Any use of the return value of this 'foo' function will have undefined
behaviour.
I didn't quite understand this. Do you say that the call: