5

In C++, operator-> has special semantics, in that if the returned type isn't a pointer, it will call operator-> again on that type. But, the intermediate value is kept as a temporary by the calling expression. This allows code to detect changes in the returned value:

template<class T>
class wrapper
{
    // ...
    T val;

    struct arrow_helper
    {
        arrow_helper(const T& temp)
            : temp(temp){}
        T temp;
        T* operator->() { return &temp; }
        ~arrow_helper() { std::cout << "modified to " << temp << '\n'; }
    };

    arrow_helper operator->() { return{ val }; }
    //return const value to prevent mistakes
    const T operator*() const { return val; }
}

and then T's members can be accessed transparently:

wrapper<Foo> f(/*...*/);
f->bar = 6;

Is there anything that could go wrong from doing this? Also, is there a way to get this effect with functions other than operator->?

EDIT: Another issue I've come across is in expressions like

f->bar = f->bar + 6;

since when the arrow_helper from the second operator-> is destructed it re-overwrites the value back to the original. My semi-elegant solution is for arrow_helper to have a T orig that is hidden, and assert(orig == *owner) in the destructor.

Dan
  • 12,409
  • 3
  • 50
  • 87

2 Answers2

3

There is no guarantee that all changes will be caught:

Foo &x = f->bar;
x = 6; /* undetected change */
Adam Sosnowski
  • 1,126
  • 9
  • 7
  • Good point, though considering [this](http://stackoverflow.com/q/9527820/603688) I'm not sure if there's a way to avoid that besides a comment saying not to. I think this ends up also being UB because you're referring to a temporary that has been destroyed. – Dan Feb 18 '15 at 21:22
0

If there is no way to grab a reference to any data within T through T's interface or otherwise, I think this should be safe. If there's any way to grab such a pointer or reference, you're done and in undefined behavior as soon as someone saves off such reference and uses it later.

Mark B
  • 95,107
  • 10
  • 109
  • 188