请考虑以下代码段:
std::shared_ptr<...> p = ...;
p->f(std::move(p));
根据cppref,operator ->
和()
具有相同的优先级,并且都是从左到右关联的。所以我假设p->
在std::move()
之前被评估,并且片段应该没问题。但是VC15却反其道而且崩溃了我的程序。这是一个VC15错误还是我在这里遇到了错误?
答案 0 :(得分:3)
您正在调用未定义的行为,因为函数调用中参数的求值顺序是而不是由标准指定,并且使用...
p->f(std::move(p));
您传递了两个参数。首先,this
,其次是std::move(p)
。但现在,有一个不那么明显的问题。你 读和写入同一个共享指针。这可能导致基本上任何东西,也称为未定义的行为。我们甚至没有提到你在这样的指针上使用std::move()
......
*this
指向*p
,但第一个(显式)参数现在保存指针本身,因此*p
无效!让我们假设这并没有使程序崩溃(不知怎的......)。然后,一旦f
离开,这可能导致对象本身被破坏。但是......当共享指针(假设只剩下一个引用)并且因此对象本身被销毁时,该函数仍然没有 。再一次,只是问题......
这只是一个例子,任何事情都可能发生在任何事情的中间。只是不读和写在同一个表达式中你就可以了:)。
BTW :We all know VS is all but standards-complaint,但无论如何,这与运营商解析的顺序和优先级无关。
修改:一切都很好如果 f()
采用通用引用(又名:转发参考,又名崩溃-rvalue-reference-black-magic-that -somehow-got-into-the-standard)或右值参考。所以,例如......
void f(std::shared_pointer<...> &&ptr)
只要你不用ptr
做错事,>>
但是,如果f
接受类型为std::remove_reference_t<decltype(*p)>>
的对象,则共享指针会移到其参数上,并且所有上述内容都会发生。