Skip to content

Trivia impact: real

The Arrow That Is Not a Pointer

an object uses -> twice before an actual pointer appears

struct Item {
  int value = 42;
};

struct Arrow {
  Item* item;
  Item* operator->() const { return item; }
};

struct Handle {
  Item item;
  Arrow operator->() { return {&item}; }
};

Handle handle;
std::cout << handle->value << "\n";

Does this compile? What does it print?

Answer
42

handle is an object, not a pointer, and the chained operator-> calls make the access work.

Why

[over.ref] interprets x->m for a class object as (x.operator->())->m when overload resolution selects that member. Handle::operator->() returns another class object, Arrow, so the same rule applies again; only Arrow::operator->() finally returns an Item* for built-in pointer member access. This recursive protocol is why a type need not be convertible to a raw pointer to support arrow syntax.

Where it shows up

Smart pointers, iterators, and proxy handles use this protocol to look pointer-like while managing ownership, validation, or indirection. Most programmers meet it through standard smart pointers; defining a multi-step proxy yourself is much less common.

Takeaway: operator-> may return another arrow-capable object before it returns a pointer.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry