@@ -12,9 +12,22 @@ class observer_ptr;
1212
1313namespace details {
1414struct control_block {
15+ enum flag_elements {
16+ flag_none = 0 ,
17+ flag_placement_allocated = 1 ,
18+ flag_expired = 2 ,
19+ flag_released = 4
20+ };
21+
1522 int refcount = 1 ;
16- bool placement_allocated = false ;
17- bool expired = false ;
23+ int flags = flag_none;
24+
25+ bool placement_allocated () const { return flags & flag_placement_allocated; }
26+ bool expired () const { return flags & flag_expired; }
27+ bool released () const { return flags & flag_released; }
28+
29+ void set_expired () { flags = flags | flag_expired; }
30+ void set_released () { flags = flags | flag_released; }
1831};
1932}
2033
@@ -61,12 +74,12 @@ class observable_unique_ptr {
6174 static void pop_ref_ (control_block* block) noexcept {
6275 --block->refcount ;
6376 if (block->refcount == 0 ) {
64- if constexpr (std::is_same_v<Deleter, std::default_delete<T>> ) {
65- if (block->placement_allocated ) {
77+ if (block-> placement_allocated () ) {
78+ if (block->released () ) {
6679 block->~control_block ();
67- delete[] reinterpret_cast <std::byte*>(block);
6880 } else {
69- delete block;
81+ block->~control_block ();
82+ delete[] (reinterpret_cast <std::byte*>(block) - sizeof (T));
7083 }
7184 } else {
7285 delete block;
@@ -75,17 +88,13 @@ class observable_unique_ptr {
7588 }
7689
7790 static void delete_and_pop_ref_ (control_block* block, T* data, Deleter& deleter) noexcept {
78- if constexpr (std::is_same_v<Deleter, std::default_delete<T>>) {
79- if (block->placement_allocated ) {
80- data->~T ();
81- } else {
82- deleter (data);
83- }
91+ if (block->placement_allocated ()) {
92+ data->~T ();
8493 } else {
8594 deleter (data);
8695 }
8796
88- block->expired = true ;
97+ block->set_expired () ;
8998
9099 pop_ref_ (block);
91100 }
@@ -331,12 +340,18 @@ class observable_unique_ptr {
331340 }
332341 }
333342
334- // / Releases ownership of the managed object.
343+ // / Releases ownership of the managed object and mark observers as expired .
335344 /* * \return A pointer to the un-managed object
345+ * \note The returned pointer, if not nullptr, becomes owned by the caller and
346+ * must be either manually deleted, or managed by another shared pointer.
347+ * Existing observer pointers will see the object as expired.
336348 */
337349 T* release () noexcept {
338350 T* old_ptr = data;
339351 if (data) {
352+ block->set_expired ();
353+ block->set_released ();
354+
340355 pop_ref_ ();
341356 block = nullptr ;
342357 data = nullptr ;
@@ -401,8 +416,9 @@ observable_unique_ptr<T> make_observable_unique(Args&& ... args) {
401416
402417 try {
403418 // Construct control block and object
404- block_type* block = new (buffer) details::control_block{1 , true , false };
405- T* ptr = new (buffer + block_size) T (std::forward<Args>(args)...);
419+ T* ptr = new (buffer) T (std::forward<Args>(args)...);
420+ block_type* block = new (buffer + object_size) details::control_block{
421+ 1 , details::control_block::flag_placement_allocated};
406422
407423 // Make owner pointer
408424 return observable_unique_ptr<T>(block, ptr);
@@ -464,9 +480,13 @@ class observer_ptr {
464480 void pop_ref_ () noexcept {
465481 --block->refcount ;
466482 if (block->refcount == 0 ) {
467- if (block->placement_allocated ) {
468- block->~control_block ();
469- delete[] reinterpret_cast <std::byte*>(block);
483+ if (block->placement_allocated ()) {
484+ if (block->released ()) {
485+ block->~control_block ();
486+ } else {
487+ block->~control_block ();
488+ delete[] reinterpret_cast <std::byte*>(block);
489+ }
470490 } else {
471491 delete block;
472492 }
@@ -686,14 +706,14 @@ class observer_ptr {
686706 /* * \return 'true' if the pointed object is valid, 'false' otherwise
687707 */
688708 bool expired () const noexcept {
689- return block == nullptr || block->expired ;
709+ return block == nullptr || block->expired () ;
690710 }
691711
692712 // / Check if this pointer points to a valid object.
693713 /* * \return 'true' if the pointed object is valid, 'false' otherwise
694714 */
695715 explicit operator bool () noexcept {
696- return block != nullptr && !block->expired ;
716+ return block != nullptr && !block->expired () ;
697717 }
698718
699719 // / Swap the content of this pointer with that of another pointer.
0 commit comments