Search code examples
c++stdstdmove

Why does std::move cause SEGFAULT in this case?


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.


Solution

  • 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.