Calling non-static member function outside of object's lifetime in C++17

The postfix expression a->f is sequenced before the evaluation of any arguments (which are indeterminately sequenced relative to one another). (See [expr.call])

The evaluation of the arguments is sequenced before the body of the function (even inline functions, see [intro.execution])

The implication, then is that calling the function itself is not undefined behavior. However, accessing any member variables or calling other member functions within would be UB per [basic.life].

So the conclusion is that this specific instance is safe per the wording, but a dangerous technique in general.


It’s true that trivial destructors do nothing at all, not even end the lifetime of the object, prior to (the plans for) C++20. So the question is, er, trivial unless we suppose a non-trivial destructor or something stronger like delete.

In that case, C++17’s ordering doesn’t help: the call (not the class member access) uses a pointer to the object (to initialize this), in violation of the rules for out-of-lifetime pointers.

Side note: if just one order were undefined, so would be the “unspecified order” prior to C++17: if any of the possibilities for unspecified behavior are undefined behavior, the behavior is undefined. (How would you tell the well-defined option was chosen? The undefined one could emulate it and then release the nasal demons.)


You seem to assume that a->f(0) has these steps (in that order for most recent C++ standard, in some logical order for previous versions):

  • evaluating *a
  • evaluating a->f (a so called bound member function)
  • evaluating 0
  • calling the bound member function a->f on the argument list (0)

But a->f doesn't have either a value or type. It's essentially a non-thing, a meaningless syntax element needed only because the grammar decomposes member access and function call, even on a member function call which by define combines member access and function call.

So asking when a->f is "evaluated" is a meaningless question: there is no such thing as a distinct evaluation step for the a->f value-less, type-less expression.

So any reasoning based on such discussions of order of evaluation of non entity is also void and null.

EDIT:

Actually this is worse than what I wrote, the expression a->f has a phony "type":

E1.E2 is “function of parameter-type-list cv returning T”.

"function of parameter-type-list cv" isn't even something that would be a valid declarator outside a class: one cannot have f() const as a declarator as in a global declaration:

int ::f() const; // meaningless

And inside a class f() const doesn't mean "function of parameter-type-list=() with cv=const”, it means member-function (of parameter-type-list=() with cv=const). There is no proper declarator for proper "function of parameter-type-list cv". It can only exist inside a class; there is no type "function of parameter-type-list cv returning T" that can be declared or that real computable expressions can have.