-4

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?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Game_Overture
  • 1,578
  • 3
  • 22
  • 34
  • 2
    http://en.cppreference.com/w/cpp/types/is_trivially_copyable#Notes . [`std::weak_ptr`](http://en.cppreference.com/w/cpp/memory/weak_ptr/weak_ptr) has nontrivial constructors, if I read it correctly. – Justin Nov 15 '17 at 21:53
  • 1
    @Justin The presence of non-trivial constructors isn’t the issue, only the presence of non-trivial copy or move constructors. However, it’s impossible for an implementation to have a trivial `std::weak_ptr` copy constructor, since copying a `weak_ptr` needs to modify the control block. – Daniel H Nov 15 '17 at 22:04
  • "_Particularly is std::weak_ptr just a pointer to the control block of a std::shared_ptr_" not "is a" but **contains a** – curiousguy Nov 24 '17 at 06:52

1 Answers1

5

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.

lisyarus
  • 15,025
  • 3
  • 43
  • 68
  • There are other uses for raw buffers, like `optional` or `variant`. But it is at least a bit weird. If you really need to copy the `weak_ptr` into a buffer, though, the correct tool is placement new. – Daniel H Nov 15 '17 at 22:07
  • @DanielH A very good point! I will add this to the answer, thank you. – lisyarus Nov 15 '17 at 22:08