C++ 关于操作员的评估命令->;和()

C++ 关于操作员的评估命令->;和(),c++,c++11,language-lawyer,operator-precedence,C++,C++11,Language Lawyer,Operator Precedence,考虑以下代码片段: std::shared_ptr<...> p = ...; p->f(std::move(p)); std::shared_ptr p=。。。; p->f(std::move(p)); 根据所述,运算符->和()具有相同的优先级,并且都是从左到右关联的。因此,我假设p->在std::move()之前进行了计算,代码片段应该是正确的。但VC15却恰恰相反,使我的程序崩溃。这是VC15错误还是我这里出了问题?您正在调用未定义的行为,因为函数调用中参数的求值顺

考虑以下代码片段:

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

根据所述,
运算符->
()
具有相同的优先级,并且都是从左到右关联的。因此,我假设
p->
std::move()
之前进行了计算,代码片段应该是正确的。但VC15却恰恰相反,使我的程序崩溃。这是VC15错误还是我这里出了问题?

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

p->f(std::move(p));
您正在传递两个参数。首先,
this
,其次,
std::move(p)
。但现在,有一个不太明显的问题。您正在读写同一个共享指针。这基本上可以导致任何情况,否则称为未定义行为。我们甚至不必提及您在这样一个指针上使用了
std::move()

*此
指向
*p
,但第一个(显式)参数现在保存指针本身,因此
*p
无效!让我们假设这并没有使程序崩溃(不知何故…)。然后,这可能导致对象本身在
f
离开后立即被销毁。但是当共享指针(假设只剩下一个引用)因此对象本身被销毁时,函数仍然没有离开。再一次,只是问题

这只是一个例子,任何事情都可能发生在任何事情的中间。只要不要读和写同一个表达式,你就会没事了:)

顺便说一句,但无论如何,这与运算符解析的顺序和优先级无关

编辑:如果
f()
采用通用引用(也称为转发引用,也称为某种程度上进入标准的折叠右值引用黑魔法)或右值引用,则一切正常。所以,举个例子

void f(std::shared_pointer<...> &&ptr)
void f(std::shared_指针和ptr)
只要你不使用ptr做坏事,一切都会变得美好和完美


但是,如果
f
接受类型为
std::remove\u reference\u t>
的对象,则共享指针将移动到其参数,并发生所有上述情况。

参数的计算顺序未指定
f
有两个参数,一个是隐式的
this
参数,另一个是显式指定的参数。在编译时,可以按照适合编译器的任何顺序对它们进行求值。正式地说,您有UB用于读取和修改同一表达式中的对象(在智能指针的某个位置)。@Cheersandhth.-Alf哦,是的,您是对的!我得到了它!我忽略了这个
指针的事情。你能回答一下吗,这样我就可以接受并结束这个问题了?@cheers-sandhth.-Alf这些是函数调用,保证不会交错。不是UB,只是没有具体说明。@T.C.每次我看到你的话,我都感到安全和有保证。对我来说,T.C.似乎只是技术委员会:)问题不在于std::move,而是相应参数的初始化。值得注意的是,这是否为UB取决于f是否使用共享指针。如果它以转发引用为例,就不会发生什么坏事。@Johanneschaub litb:这是一个重要的观点。我把它添加到答案中。