Consider the following code example:
#include <iostream>
struct outer {
struct ret {
outer &a;
ret(outer &a) : a(a) { }
template <typename T>
friend ret &operator<<(ret &r, const T &obj)
{
std::cout << "wrote: " << obj << std::endl;
return r;
}
template <typename T>
friend ret &&operator<<(ret &&r, const T &obj)
{
std::cout << "wrote: " << obj << std::endl;
return std::move(r);
}
~ret() { std::cout << "ret destroyed" << std::endl; }
};
template <typename T>
ret operator<<(const T &obj)
{
std::cout << "starting." << std::endl;
return ret(*this) << obj;
}
~outer() { std::cout << "outer destroyed" << std::endl; }
};
It consists of two nested structs, the outer of which returns an instance of the inner for the operator<<
, which in turn has an operator overload returning an (rvalue) reference to the same object.
Note how the returned object of the inner class ret
contains a reference to the outer object; when constructed *this
is passed as constructor argument.
One possible way to use this would be like this:
int main()
{
outer b;
b << 1 << 2 << 3;
b << "abc";
}
This will work as I would expect and print
starting.
wrote: 1
ret destroyed // here control returns fromouter::operator<<
wrote: 2
wrote: 3
ret destroyed
starting.
wrote: abc
ret destroyed
ret destroyed
outer destroyed
Another way would be
int main()
{
outer() << 1 << 2 << 3;
}
Which also prints the expected output
starting.
wrote: 1
ret destroyed
wrote: 2
wrote: 3
ret destroyed
outer destroyed
However, I wonder why the temporary object of type outer
is destroyed at the end of the program.
Is it possible in this example, that this temporary object created by outer()
is destroyed before the completion of the line and thus leaving the created ret
object with a dangling reference to an outer
object?
I have prepared an example on godbolt.
Update
To answer @user4581301 's concern, the outer
object is indeed destroyed directly after the ;
and not at the end of main
.