@@ -79,9 +79,38 @@ struct placement_delete
7979 }
8080};
8181
82+ template <typename T>
83+ class enable_observer_from_this ;
84+
8285namespace details {
8386
84- struct enable_observer_from_this_base {};
87+ struct enable_observer_from_this_base {
88+ using control_block = details::control_block;
89+
90+ mutable control_block* this_control_block = nullptr ;
91+
92+ void pop_ref_ () noexcept {
93+ --this_control_block->refcount ;
94+ if (this_control_block->refcount == 0 ) {
95+ delete this_control_block;
96+ }
97+ }
98+
99+ void set_control_block_ (control_block* b) noexcept {
100+ if (this_control_block) {
101+ pop_ref_ ();
102+ }
103+
104+ this_control_block = b;
105+ if (this_control_block) {
106+ ++this_control_block->refcount ;
107+ }
108+ }
109+
110+ // Friendship is required for assignment of the observer.
111+ template <typename U, typename D>
112+ friend class observable_unique_ptr_base ;
113+ };
85114
86115template <typename T, typename Deleter = oup::default_delete<T>>
87116class observable_unique_ptr_base {
@@ -122,13 +151,8 @@ class observable_unique_ptr_base {
122151 template <typename U>
123152 void set_this_observer_ (U* p) noexcept {
124153 if constexpr (std::is_convertible_v<U*,const details::enable_observer_from_this_base*>) {
125- using input_observer_type = std::decay_t <decltype (p->this_observer )>;
126- using observer_element_type = typename input_observer_type::element_type;
127- static_assert (std::is_convertible_v<U*, observer_element_type*>,
128- " incompatible type specified in enable_observer_from_this" );
129-
130154 if (p) {
131- p->this_observer . set_data_ (block, p) ;
155+ p->this_control_block = block ;
132156 ++block->refcount ;
133157 }
134158 }
@@ -876,6 +900,9 @@ class observer_ptr {
876900 // Friendship is required for enable_observer_from_this.
877901 template <typename U, typename D>
878902 friend class details ::observable_unique_ptr_base;
903+ // Friendship is required for enable_observer_from_this.
904+ template <typename U>
905+ friend class enable_observer_from_this ;
879906
880907 using control_block = details::control_block;
881908
@@ -898,6 +925,13 @@ class observer_ptr {
898925 data = d;
899926 }
900927
928+ // For enable_observer_from_this
929+ observer_ptr (control_block* b, T* d) noexcept : block(b), data(d) {
930+ if (block) {
931+ ++block->refcount ;
932+ }
933+ }
934+
901935public:
902936 // / Type of the pointed object
903937 using element_type = T;
@@ -1206,20 +1240,46 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
12061240* **Corner cases.**
12071241* - If a class A inherits from both another class B and enable_observer_from_this<A>,
12081242* and it is owned by an observable_unique_ptr<B>. The function observer_from_this()
1209- * will always return nullptr if ownership is taken from a pointer to B*, but will
1210- * be a valid pointer if ownership is taken from a pointer to A*.
1243+ * will always return nullptr if ownership is acquired from a pointer to B*, but will
1244+ * return a valid pointer if ownership is acquired from a pointer to A*. Therefore,
1245+ * make sure to always acquire ownership on the most derived type, or simply use the
1246+ * factory function make_observable_unique() which will enforce this automatically.
1247+ *
1248+ * struct B {
1249+ * virtual ~B() = default;
1250+ * };
12111251*
1212- * observable_unique_ptr<B> p(new A); // observer pointer is valid
1213- * observable_unique_ptr<B> p(static_cast<B*>(new A)); // observer pointer is nullptr
1252+ * struct A : B, enable_observer_from_this<A> {};
1253+ *
1254+ *
1255+ * observable_unique_ptr<B> good1(new A);
1256+ * dynamic_cast<A*>(good1.get())->observer_from_this(); // valid pointer
1257+ *
1258+ * observable_unique_ptr<B> good2(make_observable_unique<A>());
1259+ * dynamic_cast<A*>(good2.get())->observer_from_this(); // valid pointer
1260+ *
1261+ * // Bad: do not do this
1262+ * observable_unique_ptr<B> bad(static_cast<B*>(new A));
1263+ * dynamic_cast<A*>(bad.get())->observer_from_this(); // nullptr
1264+ *
1265+ * - Multiple inheritance. If a class A inherits from both another class B and
1266+ * enable_observer_from_this<A>, and if B also inherits from
1267+ * enable_observer_from_this<B>, then observer_from_this() will be an ambiguous
1268+ * call. But it can be resolved, and (contrary to std::shared_ptr and
1269+ * std::enable_shared_from_this) will return a valid pointer:
1270+ *
1271+ * struct B : enable_observer_from_this<B> {
1272+ * virtual ~B() = default;
1273+ * };
1274+ *
1275+ * struct A : B, enable_observer_from_this<A> {};
1276+ *
1277+ * observable_sealed_ptr<A> ptr = make_observable_sealed<A>();
1278+ * ptr->enable_observer_from_this<A>::observer_from_this(); // valid A* pointer
1279+ * ptr->enable_observer_from_this<B>::observer_from_this(); // valid B* pointer
12141280*/
12151281template <typename T>
1216- class enable_observer_from_this : public details ::enable_observer_from_this_base {
1217- mutable observer_ptr<T> this_observer;
1218-
1219- // Friendship is required for assignment of the observer.
1220- template <typename U, typename D>
1221- friend class details ::observable_unique_ptr_base;
1222-
1282+ class enable_observer_from_this : public virtual details::enable_observer_from_this_base {
12231283protected:
12241284 enable_observer_from_this () noexcept = default ;
12251285
@@ -1233,18 +1293,39 @@ class enable_observer_from_this : public details::enable_observer_from_this_base
12331293 // invalid reference.
12341294 };
12351295
1236- ~enable_observer_from_this () noexcept = default ;
1296+ ~enable_observer_from_this () noexcept {
1297+ if (this_control_block) {
1298+ pop_ref_ ();
1299+ }
1300+
1301+ this_control_block = nullptr ;
1302+ }
1303+
1304+ enable_observer_from_this& operator =(const enable_observer_from_this&) noexcept {
1305+ // Do not copy the other object's observer, this would be an
1306+ // invalid reference.
1307+ return *this ;
1308+ };
1309+
1310+ enable_observer_from_this& operator =(enable_observer_from_this&&) noexcept {
1311+ // Do not move the other object's observer, this would be an
1312+ // invalid reference.
1313+ return *this ;
1314+ };
12371315
12381316public:
12391317
1318+ using observer_element_type = T;
1319+
12401320 // / Return an observer pointer to 'this'.
12411321 /* * \return A new observer pointer pointing to 'this'.
12421322 * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
12431323 * the object was allocated on the stack, or if it is owned by another
12441324 * type of smart pointer, then this function will return nullptr.
12451325 */
12461326 observer_ptr<T> observer_from_this () {
1247- return this_observer;
1327+ return observer_ptr<T>{this_control_block,
1328+ this_control_block ? static_cast <T*>(this ) : nullptr };
12481329 }
12491330
12501331 // / Return a const observer pointer to 'this'.
@@ -1254,7 +1335,8 @@ class enable_observer_from_this : public details::enable_observer_from_this_base
12541335 * type of smart pointer, then this function will return nullptr.
12551336 */
12561337 observer_ptr<const T> observer_from_this () const {
1257- return this_observer;
1338+ return observer_ptr<const T>{this_control_block,
1339+ this_control_block ? static_cast <const T*>(this ) : nullptr };
12581340 }
12591341};
12601342
0 commit comments