关于运算符 -> 和 () 的评估顺序
Evaluation order concerning operator -> and ()
考虑这个代码片段:
std::shared_ptr<...> p = ...;
p->f(std::move(p));
根据cppref,operator ->
和()
具有相同的优先级并且都是从左到右关联的。所以我假设 p->
在 std::move()
之前被评估,并且该片段应该没问题。但 VC15 却反其道而行之,使我的程序崩溃。这是一个 VC15 错误还是我这里有问题?
您正在调用未定义的行为,因为函数调用中参数的求值顺序是不是标准指定的,并且...
p->f(std::move(p));
您有 两个 个参数被传递。首先,this
,其次,std::move(p)
。但是现在,有一个不太明显的问题。您正在 读取 和 写入同一个共享指针。这基本上可以导致任何事情,也就是所谓的未定义行为。更不用说您在这样的指针上使用 std::move()
...
*this
指向 *p
,但第一个(显式)参数现在包含指针本身,因此 *p
无效!让我们假设这并没有使程序崩溃(不知何故......)。然后,这会导致对象本身在 f
被留下时被销毁。但是......当共享指针(假设只留下一个引用)并因此对象本身被销毁时,该函数仍然存在 not 。同样,只是问题...
这只是一个例子,任何事情中间都可能发生任何事情。只需 不要 阅读 和 写在相同的表达式中就可以了:).
BTW:We 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)>>
类型的对象,共享指针被移动到它的参数上,所有上面的事情都会发生。
考虑这个代码片段:
std::shared_ptr<...> p = ...;
p->f(std::move(p));
根据cppref,operator ->
和()
具有相同的优先级并且都是从左到右关联的。所以我假设 p->
在 std::move()
之前被评估,并且该片段应该没问题。但 VC15 却反其道而行之,使我的程序崩溃。这是一个 VC15 错误还是我这里有问题?
您正在调用未定义的行为,因为函数调用中参数的求值顺序是不是标准指定的,并且...
p->f(std::move(p));
您有 两个 个参数被传递。首先,this
,其次,std::move(p)
。但是现在,有一个不太明显的问题。您正在 读取 和 写入同一个共享指针。这基本上可以导致任何事情,也就是所谓的未定义行为。更不用说您在这样的指针上使用 std::move()
...
*this
指向 *p
,但第一个(显式)参数现在包含指针本身,因此 *p
无效!让我们假设这并没有使程序崩溃(不知何故......)。然后,这会导致对象本身在 f
被留下时被销毁。但是......当共享指针(假设只留下一个引用)并因此对象本身被销毁时,该函数仍然存在 not 。同样,只是问题...
这只是一个例子,任何事情中间都可能发生任何事情。只需 不要 阅读 和 写在相同的表达式中就可以了:).
BTW:We 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)>>
类型的对象,共享指针被移动到它的参数上,所有上面的事情都会发生。