为什么 std::move 在这种情况下会导致 SEGFAULT?
Why does std::move cause SEGFAULT in this case?
为什么 std::move()
在这种情况下会导致 SEGFAULT?
#include <iostream>
struct Message {
std::string message;
};
Message * Message_Init(std::string message) {
Message * m = (Message*)calloc(1, sizeof(Message));
m->message = std::move(message);
return m;
}
int main() {
auto m = Message_Init("Hello");
return 0;
}
P.S.请不要问为什么Message
不是用通常的C++方式构造的。
如果你真的想做这样的事情,那么你可以使用placement new
。这允许您在已经分配的内存块中构造一个对象。
一些标准容器使用 placement new
来管理它们的内部对象缓冲区。
但是,它确实增加了您放置的对象的析构函数的复杂性。阅读此处了解更多信息:What uses are there for "placement new"?
#include <iostream>
#include <memory>
struct Message {
std::string message;
};
Message * Message_Init(std::string message) {
void * buf = calloc(1, sizeof(Message));
Message * m = new (buf) Message(); // placement new
m->message = std::move(message);
return m;
}
int main() {
auto m = Message_Init("Hello");
m->~Message(); // Call the destructor explicitly
free(m); // Free the memory
return 0;
}
正如@selbie 所建议的,我添加了对 Message
的析构函数的显式调用,以及对 free
的调用以释放内存。我相信对 free
的调用实际上应该指向最初由 calloc
返回的缓冲区,因为可能存在差异(所以 free(buf)
在这种情况下,但该指针在这里不可访问).
例如,如果您为多个对象分配一个缓冲区,那么在指向第二个对象的指针上调用 free
将是不正确的。
似乎对 C++ 中赋值的工作原理存在误解。如果编译器遇到涉及 class 类型的赋值操作,它会查找称为 copy/move 赋值运算符 的特殊函数。然后调用这个特殊函数来执行copy/move。一般来说,左侧 和 右侧必须初始化对象才能正常工作。
有一种特殊情况允许使用未初始化的对象。在这种情况下,要成为 copied/moved 的对象的 class 具有 普通 copy/move 赋值运算符 。然而,大多数标准库 classes 都不是平凡的 copiable/moveable,特别是 std::string
不是。
顺便说一下,你打电话给 std::move
并不重要。即使没有它,它也将是未定义的行为。在分配给它之前,您必须构造目标对象。您可以通过调用正常的 new
运算符一次性分配和构造对象,或者分配 space 并使用 placement new
在 space.
中构造对象
为什么 std::move()
在这种情况下会导致 SEGFAULT?
#include <iostream>
struct Message {
std::string message;
};
Message * Message_Init(std::string message) {
Message * m = (Message*)calloc(1, sizeof(Message));
m->message = std::move(message);
return m;
}
int main() {
auto m = Message_Init("Hello");
return 0;
}
P.S.请不要问为什么Message
不是用通常的C++方式构造的。
如果你真的想做这样的事情,那么你可以使用placement new
。这允许您在已经分配的内存块中构造一个对象。
一些标准容器使用 placement new
来管理它们的内部对象缓冲区。
但是,它确实增加了您放置的对象的析构函数的复杂性。阅读此处了解更多信息:What uses are there for "placement new"?
#include <iostream>
#include <memory>
struct Message {
std::string message;
};
Message * Message_Init(std::string message) {
void * buf = calloc(1, sizeof(Message));
Message * m = new (buf) Message(); // placement new
m->message = std::move(message);
return m;
}
int main() {
auto m = Message_Init("Hello");
m->~Message(); // Call the destructor explicitly
free(m); // Free the memory
return 0;
}
正如@selbie 所建议的,我添加了对 Message
的析构函数的显式调用,以及对 free
的调用以释放内存。我相信对 free
的调用实际上应该指向最初由 calloc
返回的缓冲区,因为可能存在差异(所以 free(buf)
在这种情况下,但该指针在这里不可访问).
例如,如果您为多个对象分配一个缓冲区,那么在指向第二个对象的指针上调用 free
将是不正确的。
似乎对 C++ 中赋值的工作原理存在误解。如果编译器遇到涉及 class 类型的赋值操作,它会查找称为 copy/move 赋值运算符 的特殊函数。然后调用这个特殊函数来执行copy/move。一般来说,左侧 和 右侧必须初始化对象才能正常工作。
有一种特殊情况允许使用未初始化的对象。在这种情况下,要成为 copied/moved 的对象的 class 具有 普通 copy/move 赋值运算符 。然而,大多数标准库 classes 都不是平凡的 copiable/moveable,特别是 std::string
不是。
顺便说一下,你打电话给 std::move
并不重要。即使没有它,它也将是未定义的行为。在分配给它之前,您必须构造目标对象。您可以通过调用正常的 new
运算符一次性分配和构造对象,或者分配 space 并使用 placement new
在 space.