为什么将 std::move(object) 和此对象的成员传递给函数会导致 SIGSEGV
Why passing std::move(object) and member of this object to function causes 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.ptr
或 std::move(c)
将首先被评估。在未指定的函数调用中评估顺序参数。在您的情况下,似乎首先评估 std::move(c)
,将 c.ptr
保留为 nullptr
。然后你执行 cout << *x << endl
尝试取消引用 *x
,其中 x
是 nullptr
.
它是按值传递的,但是:
foo(c.ptr, std::move(c));
未指定参数的顺序that are passed to a function call get evaluated。
Order of evaluation of the operands of almost all C++ operators
(including the order of evaluation of function arguments in a
function-call expression ... ) is unspecified.
"Unspecified" 表示它们可以按任意顺序求值。每次 运行 程序时,顺序甚至可能不同。您的编译器选择生成首先使用 std::move
评估第二个参数的代码。因此,您的移动构造函数将指针移出对象,将其设置为空。然后,c.ptr
被评估,按值传递 now-null 指针。
以下代码生成 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.ptr
或 std::move(c)
将首先被评估。在未指定的函数调用中评估顺序参数。在您的情况下,似乎首先评估 std::move(c)
,将 c.ptr
保留为 nullptr
。然后你执行 cout << *x << endl
尝试取消引用 *x
,其中 x
是 nullptr
.
它是按值传递的,但是:
foo(c.ptr, std::move(c));
未指定参数的顺序that are passed to a function call get evaluated。
Order of evaluation of the operands of almost all C++ operators (including the order of evaluation of function arguments in a function-call expression ... ) is unspecified.
"Unspecified" 表示它们可以按任意顺序求值。每次 运行 程序时,顺序甚至可能不同。您的编译器选择生成首先使用 std::move
评估第二个参数的代码。因此,您的移动构造函数将指针移出对象,将其设置为空。然后,c.ptr
被评估,按值传递 now-null 指针。