为什么 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.

中构造对象