Your first example does not guarantee copy elision either. Both the first and second example may elide the copy, but it is up to the compiler. However, in the first case it is much simpler for the compiler to recognize the pattern and apply the optimization. So you are likely to see it applied in the first case, but less likely in the second case where it may be impossible for the compiler to track which of the two local objects should be constructed as the result object, although it may still be possible depending on the exact circumstances.
Using the
SomeBigObject obj;
func(&obj);
form doesn't fix that issue either though. The function parameter can be easily identified with only one of the two localX objects, which is precisely why it is generally harder for a compiler to do the optimization for such cases.
Also note that the article you link was written before C++17 when some copy elision became mandatory for the first time. Before C++17 it was all up to the compiler. The article just reflects the behavior of typical implementations (at the time?).
The rule now is pretty simple: If you initialize an object from a prvalue of the same type (up to cv-qualifiers), then copy elision is guaranteed. This applies to chained initialization through multiple prvalues and also function calls as well.
func() is a prvalue of type SomeBigObject, so in SomeBigObject obj = func(); copy elision is mandatory in as far as there will be no object as the return value of the function distinct from obj. (since C++17)
In both your function implementations the return operand is however a lvalue and so it isn't guaranteed that obj and local/localX will be identified with one-another. Under certain circumstances satisfied here, the compiler may still do this identification and eliminate the copy/move. But that is always non-mandatory.
So ideally you want to not return a local variable, but construct the return value directly in the return statement if the logic of the function allows that. Or at least try to scope each local variable used as a return operand so that all return statements in its scope return only this variable.
I am not aware of any tool for the common compilers or in the language to statically check at compile-time whether or not the non-mandatory named return value optimization is applied to a function.