在这种情况下,为什么STD ::移动原因是Segfault?

发布于 2025-01-24 08:42:38 字数 443 浏览 1 评论 0原文

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

ps 请不要询问为什么消息不以通常的C ++方式构建。

Why does std::move() cause a SEGFAULT in this case?

#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. Please don't ask why Message is not constructed in a usual C++ manner.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一梦浮鱼 2025-01-31 08:42:38

如果您真的想做这样的事情,则可以使用安置新。这使您可以在已经分配的一块内存中构造一个对象。

一些标准容器使用放置新来管理其内部对象缓冲区。

但是,它确实增加了与您所处物体的破坏者的并发症。在此处阅读以获取更多信息:有哪些用途用于“位置新”?

#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的destructor上添加了一个明确的调用,也向free呼叫以处理内存。我相信免费的电话实际上应该指向最初由calloc返回的缓冲区,因为可能会有差异(因此free(buf)在这种情况下,但是在这里无法访问该指针)。

例如,如果您为多个对象分配缓冲区,则在指向第二个对象的指针上调用免费是不正确的。

If you really want to do something like this, then you can use placement new. This allows you to construct an object in a chunk of memory that is already allocated.

Several of the standard containers use placement new to manage their internal buffers of objects.

However, it does add complications with the destructors of the objects you place. Read here for more info: 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;
}

As @selbie suggested, I have added an explicit call to the destructor of Message, and also a call to free to deallocate the memory. I believe that the call to free should actually have pointed to the buffer originally returned by calloc since there could be a difference (so free(buf) in this case, but that pointer is not accessible here).

For example if you allocate a buffer for several objects, then calling free on the pointer to the second object would not be correct.

逆流 2025-01-31 08:42:38

关于C ++的分配的工作方式似乎存在误解。如果编译器遇到具有涉及类类型的评估操作,则它将寻找一个称为 copy/move分配运算符的特殊功能。然后调用此特殊功能执行复制/移动。一般而言,左手右侧必须是初始化的对象才能正确工作。

在某些情况下,允许它使用非初始化的对象。在这种情况下,要复制/移动的对象的类具有一个琐碎的副本/移动式操作员。但是,大多数标准库类都不是微不足道的共配/可移动,尤其是std :: String不是。

顺便说一句,您打电话给std ::移动并不重要。即使没有它,它也是不确定的行为。您必须在分配目标对象之前构造目标对象。您可以通过调用正常new运算符或分配空间并使用放置 new new new 在该空间中构造对象。

There seems to be a misunderstanding about how assignment in C++ works. If the compiler encounters a assigment operation with class types involved, it looks for a special function called the copy/move assignment operator. This special function is then called to perform the copy/move. Generally speaking the left hand side and the right hand side have to be initialized objects for this to work correctly.

There is a special case in which it is allowed to use uninitialized objects. That is the case where the class of the objects that are to be copied/moved has a trivial copy/move assigment operator. However most of the standard library classes are not trivially copiable/moveable and in particular std::string is not.

By the way it does not matter that you called std::move. Even without it, it would be undefined behaviour. You have to construct the target object before assigning to it. You can do that by either allocating and constructing the object in one shot by calling the normal new operator, or by allocating the space and use placement new to construct the object in that space.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文