为什么std::move会导致SEGFAULT ?



为什么在这种情况下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;
}

注:请不要问为什么Message不是用通常的c++方式构造的。

如果你真的想做这样的事情,那么你可以使用placement new。这允许您在已经分配的内存块中构造对象。

几个标准容器使用placement new来管理它们的对象的内部缓冲区。

但是,它确实增加了所放置对象的析构函数的复杂性。阅读这里了解更多信息:"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++中的赋值操作似乎存在误解。如果编译器遇到涉及类类型的赋值操作,它会查找一个称为复制/移动赋值操作符的特殊函数。然后调用这个特殊函数来执行复制/移动。一般来说,左边的右边必须是初始化的对象才能正常工作

有一种特殊情况,允许使用未初始化的对象。在这种情况下,要复制/移动的对象的类具有平凡的复制/移动赋值操作符。然而,大多数标准库类都不能简单地复制/移动,特别是std::string

顺便说一下,调用std::move并不重要。即使没有它,这也是未定义的行为。在给目标对象赋值之前,必须先构造它。你可以通过调用普通的new操作符一次性分配和构造对象,或者通过分配空间并使用位置new来在该空间中构造对象。

最新更新