0

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 from outer::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.

HerpDerpington
  • 3,751
  • 4
  • 27
  • 43
  • 1
    Well elaborated question. Unfortunately, needed a bit more research and example minimisation. – LogicStuff Nov 07 '19 at 19:47
  • 1
    Pop a `std::cout << "Exiting"<< std::endl;` after `outer() << 1 << 2 << 3;` to see if the temporary `outer` really is going out of scope at the end of `main`. Right now it could be going out of scope at the end of the line as expected and there is no good way to tell the end of the line from the end of `main`. – user4581301 Nov 07 '19 at 20:27

0 Answers0