关于运算符 -> 和 () 的评估顺序

Evaluation order concerning operator -> and ()

考虑这个代码片段:

std::shared_ptr<...> p = ...;
p->f(std::move(p));

根据cpprefoperator ->() 具有相同的优先级并且都是从左到右关联的。所以我假设 p->std::move() 之前被评估,并且该片段应该没问题。但 VC15 却反其道而行之,使我的程序崩溃。这是一个 VC15 错误还是我这里有问题?

您正在调用未定义的行为,因为函数调用中参数的求值顺序是不是标准指定的,并且...

p->f(std::move(p));

您有 两个 个参数被传递。首先,this,其次,std::move(p)。但是现在,有一个不太明显的问题。您正在 读取 写入同一个共享指针。这基本上可以导致任何事情,也就是所谓的未定义行为。更不用说您在这样的指针上使用 std::move()...

*this 指向 *p,但第一个(显式)参数现在包含指针本身,因此 *p 无效!让我们假设这并没有使程序崩溃(不知何故......)。然后,这会导致对象本身在 f 被留下时被销毁。但是......当共享指针(假设只留下一个引用)并因此对象本身被销毁时,该函数仍然存在 not 。同样,只是问题...

这只是一个例子,任何事情中间都可能发生任何事情。只需 不要 阅读 写在相同的表达式中就可以了:).

BTWWe all know VS is all but standards-complaint,不过不管怎么说,这与运算符解析的顺序和优先级无关。

编辑:一切正常iff()取一个通用引用(a.k.a:转发引用, a.k.a collapsed-rvalue-reference-black-magic-that-somehow-got-into-the-standard) 或右值引用。所以,例如...

void f(std::shared_pointer<...> &&ptr)

只要不和ptr...

做坏事,一切都会变得美好

但是,如果f接受一个std::remove_reference_t<decltype(*p)>>类型的对象,共享指针被移动到它的参数上,所有上面的事情都会发生。