为什么传递std ::移动(对象)和此对象的成员函数会导致sigsegv



以下代码在sigsegv中导致我不明白为什么是。

#include <iostream>
using namespace std;
struct C {
    C(int x) { ptr = new int(x); }
    C(C&& c) { ptr = c.ptr; c.ptr = nullptr; }
    int* ptr;
};
void foo(int* x, C c) {
    cout << *x  << endl;
}
int main() {
    C c(10);
    foo(c.ptr, std::move(c));   
    return 0;
}

我希望指针c.ptr会按值通过值传递给函数foo,但是它的行为类似于引用。

现在,如果我更改参数的排序:void foo(c c,int* x),那么问题就会消失。另一个解决方案是在致电x之前创建C.Ptr的本地副本,而不是将本地副本传递给foo。

我想了解为什么我不能在上面的示例代码中通过值传递c.ptr。

它是按值传递的,但是:

foo(c.ptr, std::move(c));

未指定的是,将传递给函数调用的参数得到评估。

几乎所有C 操作员的操作数评估顺序 (包括函数参数的评估顺序 函数通话表达式...)未指定。

"未指定"表示可以按任何顺序对其进行评估。每次运行程序时,订单甚至都可能不同。您的编译器选择首先使用std::move评估第二个参数的代码。因此,您的移动构造函数将指针从对象移出,将其设置为空。然后,对c.ptr进行评估,按值传递现在无效的指针。

当您致电foo(c.ptr, std::move(c));时,您不能确保首先评估c.ptrstd::move(c)。在函数调用中评估订单参数未指定。在您的情况下,std::move(c)似乎将首先评估,而c.ptr则为nullptr。然后,您进行cout << *x << endl,试图放置*x,其中xnullptr

最新更新