Search code examples
c++c++11shared-ptrweak-ptrdata-representation

Can I memcpy std::weak_ptr?


First off, what is the typical implementation of a std::weak_ptr? Particularly is std::weak_ptr just a pointer to the control block of a std::shared_ptr?

If all the std::shared_ptr references are gone is the internal control block deleted? If so, how does std::weak_ptr::expired() function properly if that memory is re-purposed?


I have an object that contains a std::weak_ptr, and I want to memcpy the object to a buffer to be processed later. Is doing so going to break the internal workings of the smart pointer in some way?


Solution

  • When all std::shared_ptr objects are gone, the control block still exists (that's how std::weak_ptr's work), only the referenced object is deleted.

    Now, a C++ object can be safely copied via std::memcpy only if it is trivially copyable. Checking the requirements of TriviallyCopyable concept, we see that std::weak_ptr does not satisfy it due to having a non-trivial copy constructor. In fact, this constructor will increase the weak-pointers-counter inside the control block, so copying it with std::memcpy would break its invariants.

    To be honest, storing an std::weak_ptr in a raw buffer sounds like a terrible idea in usual code. Buffers are normally used for serialization, sending/writing data, etc, and all these tasks are nonsensical for a smart pointer. If, however, you are absolutely sure that you need to store it in a buffer, you need placement new:

    std::weak_ptr<T> the_one_i_want_to_copy;
    
    std::weak_ptr<T> * buffer = ...;
    new (buffer) std::weak_ptr<T> { the_one_i_want_to_copy };
    

    Notice the (buffer) after new: it tells new not to allocate the memory, but to use an already prepared place (thus placement new). When preparing buffer, be sure to provide the required size and alignment.