Consider this code snippet:
std::shared_ptr<...> p = ...;
p->f(std::move(p));
According to cppref, operator ->
and ()
are of the same precedence and are both left-to-right associative. So I presume p->
is evaluated before std::move()
, and the snippet should be fine. But VC15 does the opposite and crashes my program. Is this a VC15 bug or I have just got something wrong here?
You're invoking undefined behaviour, because the order of evaluation of arguments in a function call is not specified by the standard, and with...
p->f(std::move(p));
You have two arguments being passed. First of all, this
, and secondly, std::move(p)
. But now, there's a not-so-obvious problem. You're both reading and writing to the same shared pointer. This can lead to basically anything, otherwise known as undefined behaviour. Let's not even mention you're using std::move()
on such a pointer...
*this
is pointing to *p
, but the first (explicit) argument now holds the pointer itself, so *p
is not valid! Let's suppose this didn't crashed the program (somehow...). Then, this can lead to the object itself being destroyed as soon as f
is left. But... when the shared pointer (assuming just a single reference is left) and thus the object itself is destroyed, the function has not still left. Again, just problems...
That was just an example, and anything could have happened in the middle of anything. Just don't read and write in the same expression and you'll be okay :).
BTW: We all know VS is all but standards-complaint, but anyway, this has nothing to do with the order and precedence of operator resolution.
Edit: Everything is okay if f()
takes a universal reference (a.k.a: forwarding reference, a.k.a collapsed-rvalue-reference-black-magic-that-somehow-got-into-the-standard) or a rvalue reference. So, for example...
void f(std::shared_pointer<...> &&ptr)
Everything will go beatiful and perfect, as long as you don't do bad things with ptr
...
But, if f
takes an object of type std::remove_reference_t<decltype(*p)>>
, the shared pointer is moved on to its argument and all the above stuff happens.