Skip to content

Commit 1bf25e0

Browse files
committed
Added enable_observer_from_this
1 parent e719356 commit 1bf25e0

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

include/oup/observable_unique_ptr.hpp

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ namespace oup {
1111
template<typename T>
1212
class observer_ptr;
1313

14+
template<typename T>
15+
class enable_observer_from_this;
16+
1417
namespace details {
1518
struct control_block {
1619
enum flag_elements {
@@ -106,13 +109,24 @@ class observable_unique_ptr_base {
106109
delete_and_pop_ref_(block, ptr_deleter.data, ptr_deleter);
107110
}
108111

112+
/// Fill in the observer pointer for objects inheriting from enable_observer_from_this.
113+
void set_this_observer() noexcept {
114+
if constexpr (std::is_base_of_v<enable_observer_from_this<T>, T>) {
115+
if (ptr_deleter.data) {
116+
ptr_deleter.data->this_observer = *this;
117+
}
118+
}
119+
}
120+
109121
/// Private constructor using pre-allocated control block.
110122
/** \param ctrl The control block pointer
111123
* \param value The pointer to own
112124
* \note This is used by make_observable_unique().
113125
*/
114126
observable_unique_ptr_base(control_block_type* ctrl, T* value) noexcept :
115-
block(ctrl), ptr_deleter{Deleter{}, value} {}
127+
block(ctrl), ptr_deleter{Deleter{}, value} {
128+
set_this_observer();
129+
}
116130

117131
/// Private constructor using pre-allocated control block.
118132
/** \param ctrl The control block pointer
@@ -121,7 +135,9 @@ class observable_unique_ptr_base {
121135
* \note This is used by make_observable_sealed().
122136
*/
123137
observable_unique_ptr_base(control_block_type* ctrl, T* value, Deleter del) noexcept :
124-
block(ctrl), ptr_deleter{std::move(del), value} {}
138+
block(ctrl), ptr_deleter{std::move(del), value} {
139+
set_this_observer();
140+
}
125141

126142
// Friendship is required for conversions.
127143
template<typename U>
@@ -181,6 +197,7 @@ class observable_unique_ptr_base {
181197
observable_unique_ptr_base(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
182198
value.block = nullptr;
183199
value.ptr_deleter.data = nullptr;
200+
set_this_observer();
184201
}
185202

186203
/// Transfer ownership by implicit casting
@@ -195,6 +212,7 @@ class observable_unique_ptr_base {
195212
observable_unique_ptr_base(value.block, value.ptr_deleter.data, std::move(value.ptr_deleter)) {
196213
value.block = nullptr;
197214
value.ptr_deleter.data = nullptr;
215+
set_this_observer();
198216
}
199217

200218
/// Transfer ownership by explicit casting
@@ -209,6 +227,7 @@ class observable_unique_ptr_base {
209227
observable_unique_ptr_base(manager.block, value) {
210228
manager.block = nullptr;
211229
manager.ptr_deleter.data = nullptr;
230+
set_this_observer();
212231
}
213232

214233
/// Transfer ownership by explicit casting
@@ -223,6 +242,7 @@ class observable_unique_ptr_base {
223242
observable_unique_ptr_base(manager.block, value, std::move(del)) {
224243
manager.block = nullptr;
225244
manager.ptr_deleter.data = nullptr;
245+
set_this_observer();
226246
}
227247

228248
/// Transfer ownership by implicit casting
@@ -240,6 +260,7 @@ class observable_unique_ptr_base {
240260
ptr_deleter.data = value.ptr_deleter.data;
241261
value.ptr_deleter.data = nullptr;
242262
static_cast<Deleter&>(ptr_deleter) = std::move(static_cast<Deleter&>(value.ptr_deleter));
263+
set_this_observer();
243264

244265
return *this;
245266
}
@@ -262,6 +283,7 @@ class observable_unique_ptr_base {
262283
ptr_deleter.data = value.ptr_deleter.data;
263284
value.ptr_deleter.data = nullptr;
264285
static_cast<Deleter&>(ptr_deleter) = std::move(static_cast<Deleter&>(ptr_deleter));
286+
set_this_observer();
265287

266288
return *this;
267289
}
@@ -299,6 +321,8 @@ class observable_unique_ptr_base {
299321
using std::swap;
300322
swap(block, other.block);
301323
swap(ptr_deleter, other.ptr_deleter);
324+
other.set_this_observer();
325+
set_this_observer();
302326
}
303327

304328
/// Replaces the managed object with a null pointer.
@@ -1169,6 +1193,64 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
11691193
return first.get() != second.get();
11701194
}
11711195

1196+
/// Enables creating an observer pointer from 'this'.
1197+
/** If an object must be able to create an observer pointer to itself,
1198+
* without having direct access to the owner pointer (unique or sealed),
1199+
* then the object's class can inherit from enable_observer_from_this.
1200+
* This provides the observer_from_this() member function, which returns
1201+
* a new observer pointer to the object. For this mechanism to work,
1202+
* the class must inherit publicly from enable_observer_from_this,
1203+
* and the object must be owned by a unique or sealed pointer when
1204+
* calling observer_from_this(). If the latter condition is not satisfied,
1205+
* i.e., the object was allocated on the stack, or is owned by another
1206+
* type of smart pointer, then observer_from_this() will return nullptr.
1207+
*/
1208+
template<typename T>
1209+
class enable_observer_from_this {
1210+
observer_ptr<T> this_observer;
1211+
1212+
// Friendship is required for assignement of the observer.
1213+
template<typename U, typename D>
1214+
friend class observable_unique_ptr_base;
1215+
1216+
protected:
1217+
enable_observer_from_this() noexcept = default;
1218+
1219+
enable_observer_from_this(const enable_observer_from_this&) noexcept {
1220+
// Do not copy the other object's observer, this would be an
1221+
// invalid reference.
1222+
};
1223+
1224+
enable_observer_from_this(enable_observer_from_this&&) noexcept {
1225+
// Do not move the other object's observer, this would be an
1226+
// invalid reference.
1227+
};
1228+
1229+
~enable_observer_from_this() noexcept = default;
1230+
1231+
public:
1232+
1233+
/// Return an observer pointer to 'this'.
1234+
/** \return A new observer pointer pointing to 'this'.
1235+
* \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1236+
* the object was allocated on the stack, or if it is owned by another
1237+
* type of smart pointer, then this function will return nullptr.
1238+
*/
1239+
observer_ptr<T> observer_from_this() {
1240+
return this_observer;
1241+
}
1242+
1243+
/// Return a const observer pointer to 'this'.
1244+
/** \return A new observer pointer pointing to 'this'.
1245+
* \note If 'this' is not owned by a unique or sealed pointer, i.e., if
1246+
* the object was allocated on the stack, or if it is owned by another
1247+
* type of smart pointer, then this function will return nullptr.
1248+
*/
1249+
observer_ptr<const T> observer_from_this() const {
1250+
return this_observer;
1251+
}
1252+
};
1253+
11721254
}
11731255

11741256
#endif

0 commit comments

Comments
 (0)