@@ -258,7 +258,11 @@ class observable_unique_ptr_base {
258258 */
259259 template <typename U, typename D>
260260 observable_unique_ptr_base (observable_unique_ptr_base<U,D>&& manager, T* value) noexcept :
261- observable_unique_ptr_base (manager.block, value) {
261+ observable_unique_ptr_base (value != nullptr ? manager.block : nullptr , value) {
262+ if (manager.ptr_deleter .data != nullptr && value == nullptr ) {
263+ manager.delete_and_pop_ref_ ();
264+ }
265+
262266 manager.block = nullptr ;
263267 manager.ptr_deleter .data = nullptr ;
264268 }
@@ -272,7 +276,11 @@ class observable_unique_ptr_base {
272276 */
273277 template <typename U, typename D>
274278 observable_unique_ptr_base (observable_unique_ptr_base<U,D>&& manager, T* value, Deleter del) noexcept :
275- observable_unique_ptr_base (manager.block, value, std::move(del)) {
279+ observable_unique_ptr_base (value != nullptr ? manager.block : nullptr , value, std::move(del)) {
280+ if (manager.ptr_deleter .data != nullptr && value == nullptr ) {
281+ manager.delete_and_pop_ref_ ();
282+ }
283+
276284 manager.block = nullptr ;
277285 manager.ptr_deleter .data = nullptr ;
278286 }
@@ -520,7 +528,10 @@ class observable_unique_ptr :
520528 * \param value The casted pointer value to take ownership of
521529 * \note After this observable_unique_ptr is created, the source
522530 * pointer is set to null and looses ownership. The deleter
523- * is default constructed.
531+ * is default constructed. The raw pointer `value`
532+ * must be obtained by casting the raw pointer managed by `manager`
533+ * (const cast, dynamic cast, etc), such that deleting `value` has
534+ * the same effect as deleting the pointer owned by `manager`.
524535 */
525536 template <typename U, typename D, typename V, typename enable =
526537 std::enable_if_t <std::is_convertible_v<V*,T*>>>
@@ -534,7 +545,10 @@ class observable_unique_ptr :
534545 * \param value The casted pointer value to take ownership of
535546 * \param del The deleter to use in the new pointer
536547 * \note After this observable_unique_ptr is created, the source
537- * pointer is set to null and looses ownership.
548+ * pointer is set to null and looses ownership. The raw pointer `value`
549+ * must be obtained by casting the raw pointer managed by `manager`
550+ * (const cast, dynamic cast, etc), such that deleting `value` has
551+ * the same effect as deleting the pointer owned by `manager`.
538552 */
539553 template <typename U, typename D, typename V, typename enable =
540554 std::enable_if_t <std::is_convertible_v<V*,T*>>>
@@ -728,10 +742,14 @@ class observable_sealed_ptr :
728742 /* * \param manager The smart pointer to take ownership from
729743 * \param value The casted pointer value to take ownership of
730744 * \note After this `observable_sealed_ptr` is created, the source
731- * pointer is set to null and looses ownership.
745+ * pointer is set to null and looses ownership. The raw pointer `value`
746+ * must be obtained by casting the raw pointer managed by `manager`
747+ * (const cast, dynamic cast, etc), such that deleting `value` has
748+ * the same effect as deleting the pointer owned by `manager`.
732749 */
733- template <typename U>
734- observable_sealed_ptr (observable_sealed_ptr<U>&& manager, T* value) noexcept :
750+ template <typename U, typename V, typename enable =
751+ std::enable_if_t <std::is_convertible_v<V*,T*>>>
752+ observable_sealed_ptr (observable_sealed_ptr<U>&& manager, V* value) noexcept :
735753 base (std::move(manager), value) {}
736754
737755 // / Transfer ownership by implicit casting
@@ -996,6 +1014,24 @@ class observer_ptr {
9961014 }
9971015 }
9981016
1017+ // / Copy an existing `observer_ptr` instance with explicit casting
1018+ /* * \param manager The observer pointer to copy the observed data from
1019+ * \param value The casted pointer value to observe
1020+ * \note After this smart pointer is created, the source
1021+ * pointer is set to null and looses ownership. The deleter
1022+ * is default constructed. The raw pointer `value` may or may
1023+ * not be related to the raw pointer observed by `manager`.
1024+ * This could be a pointer to any other object which is known to
1025+ * have the same lifetime.
1026+ */
1027+ template <typename U>
1028+ observer_ptr (const observer_ptr<U>& manager, T* value) noexcept :
1029+ block (value != nullptr ? manager.block : nullptr ), data(value) {
1030+ if (block) {
1031+ ++block->refcount ;
1032+ }
1033+ }
1034+
9991035 // / Move from an existing `observer_ptr` instance
10001036 /* * \param value The existing observer pointer to move from
10011037 * \note After this `observer_ptr` is created, the source
@@ -1018,6 +1054,27 @@ class observer_ptr {
10181054 value.data = nullptr ;
10191055 }
10201056
1057+ // / Move from an existing `observer_ptr` instance with explicit casting
1058+ /* * \param manager The observer pointer to copy the observed data from
1059+ * \param value The casted pointer value to observe
1060+ * \note After this smart pointer is created, the source
1061+ * pointer is set to null and looses ownership. The deleter
1062+ * is default constructed. The raw pointer `value` may or may
1063+ * not be related to the raw pointer observed by `manager`.
1064+ * This could be a pointer to any other object which is known to
1065+ * have the same lifetime.
1066+ */
1067+ template <typename U>
1068+ observer_ptr (observer_ptr<U>&& manager, T* value) noexcept :
1069+ block (value != nullptr ? manager.block : nullptr ), data(value) {
1070+ if (manager.data != nullptr && value == nullptr ) {
1071+ manager.pop_ref_ ();
1072+ }
1073+
1074+ manager.block = nullptr ;
1075+ manager.data = nullptr ;
1076+ }
1077+
10211078 // / Point to another owning pointer.
10221079 /* * \param owner The new owner pointer to observe
10231080 * \note This operator only takes part in overload resolution if
@@ -1320,9 +1377,6 @@ class enable_observer_from_this : public virtual details::enable_observer_from_t
13201377 };
13211378
13221379public:
1323-
1324- using observer_element_type = T;
1325-
13261380 // / Return an observer pointer to 'this'.
13271381 /* * \return A new observer pointer pointing to 'this'.
13281382 * \note If 'this' is not owned by a unique or sealed pointer, i.e., if
@@ -1352,6 +1406,147 @@ class enable_observer_from_this : public virtual details::enable_observer_from_t
13521406 }
13531407};
13541408
1409+ // / Perform a `static_cast` for an `observable_unique_ptr`.
1410+ /* * \param ptr The pointer to cast
1411+ * \note Ownership will be transfered to the returned pointer.
1412+ If the input pointer is null, the output pointer will also be null.
1413+ */
1414+ template <typename U, typename T>
1415+ observable_unique_ptr<U> static_pointer_cast (observable_unique_ptr<T>&& ptr) {
1416+ return observable_unique_ptr<U>(std::move (ptr), static_cast <U*>(ptr.get ()));
1417+ }
1418+
1419+ // / Perform a `static_cast` for an `observable_unique_ptr`.
1420+ /* * \param ptr The pointer to cast
1421+ * \note Ownership will be transfered to the returned pointer.
1422+ If the input pointer is null, the output pointer will also be null.
1423+ */
1424+ template <typename U, typename T>
1425+ observable_sealed_ptr<U> static_pointer_cast (observable_sealed_ptr<T>&& ptr) {
1426+ return observable_sealed_ptr<U>(std::move (ptr), static_cast <U*>(ptr.get ()));
1427+ }
1428+
1429+ // / Perform a `static_cast` for an `observer_ptr`.
1430+ /* * \param ptr The pointer to cast
1431+ * \note A new observer is returned, the input observer is not modified.
1432+ If the input pointer is null, the output pointer will also be null.
1433+ */
1434+ template <typename U, typename T>
1435+ observer_ptr<U> static_pointer_cast (const observer_ptr<T>& ptr) {
1436+ // NB: can use raw_get() as static cast of an expired pointer is fine
1437+ return observer_ptr<U>(ptr, static_cast <U*>(ptr.raw_get ()));
1438+ }
1439+
1440+ // / Perform a `static_cast` for an `observer_ptr`.
1441+ /* * \param ptr The pointer to cast
1442+ * \note A new observer is returned, the input observer is set to null.
1443+ If the input pointer is null, the output pointer will also be null.
1444+ */
1445+ template <typename U, typename T>
1446+ observer_ptr<U> static_pointer_cast (observer_ptr<T>&& ptr) {
1447+ // NB: can use raw_get() as static cast of an expired pointer is fine
1448+ return observer_ptr<U>(std::move (ptr), static_cast <U*>(ptr.raw_get ()));
1449+ }
1450+
1451+ // / Perform a `const_cast` for an `observable_unique_ptr`.
1452+ /* * \param ptr The pointer to cast
1453+ * \note Ownership will be transfered to the returned pointer.
1454+ If the input pointer is null, the output pointer will also be null.
1455+ */
1456+ template <typename U, typename T>
1457+ observable_unique_ptr<U> const_pointer_cast (observable_unique_ptr<T>&& ptr) {
1458+ return observable_unique_ptr<U>(std::move (ptr), const_cast <U*>(ptr.get ()));
1459+ }
1460+
1461+ // / Perform a `const_cast` for an `observable_unique_ptr`.
1462+ /* * \param ptr The pointer to cast
1463+ * \note Ownership will be transfered to the returned pointer.
1464+ If the input pointer is null, the output pointer will also be null.
1465+ */
1466+ template <typename U, typename T>
1467+ observable_sealed_ptr<U> const_pointer_cast (observable_sealed_ptr<T>&& ptr) {
1468+ return observable_sealed_ptr<U>(std::move (ptr), const_cast <U*>(ptr.get ()));
1469+ }
1470+
1471+ // / Perform a `const_cast` for an `observer_ptr`.
1472+ /* * \param ptr The pointer to cast
1473+ * \note A new observer is returned, the input observer is not modified.
1474+ If the input pointer is null, the output pointer will also be null.
1475+ */
1476+ template <typename U, typename T>
1477+ observer_ptr<U> const_pointer_cast (const observer_ptr<T>& ptr) {
1478+ // NB: can use raw_get() as const cast of an expired pointer is fine
1479+ return observer_ptr<U>(ptr, const_cast <U*>(ptr.raw_get ()));
1480+ }
1481+
1482+ // / Perform a `const_cast` for an `observer_ptr`.
1483+ /* * \param ptr The pointer to cast
1484+ * \note A new observer is returned, the input observer is set to null.
1485+ If the input pointer is null, the output pointer will also be null.
1486+ */
1487+ template <typename U, typename T>
1488+ observer_ptr<U> const_pointer_cast (observer_ptr<T>&& ptr) {
1489+ // NB: can use raw_get() as const cast of an expired pointer is fine
1490+ return observer_ptr<U>(std::move (ptr), const_cast <U*>(ptr.raw_get ()));
1491+ }
1492+
1493+ // / Perform a `dynamic_cast` for an `observable_unique_ptr`.
1494+ /* * \param ptr The pointer to cast
1495+ * \note Ownership will be transfered to the returned pointer unless the cast
1496+ * fails, in which case ownership remains in the original pointer, std::bad_cast
1497+ * is thrown, and no memory is leaked. If the input pointer is null,
1498+ * the output pointer will also be null.
1499+ */
1500+ template <typename U, typename T>
1501+ observable_unique_ptr<U> dynamic_pointer_cast (observable_unique_ptr<T>&& ptr) {
1502+ if (ptr == nullptr ) {
1503+ return observable_unique_ptr<U>{};
1504+ }
1505+
1506+ U& casted_object = dynamic_cast <U&>(*ptr.get ());
1507+ return observable_unique_ptr<U>(std::move (ptr), &casted_object);
1508+ }
1509+
1510+ // / Perform a `dynamic_cast` for an `observable_unique_ptr`.
1511+ /* * \param ptr The pointer to cast
1512+ * \note Ownership will be transfered to the returned pointer unless the cast
1513+ * fails, in which case ownership remains in the original pointer, and
1514+ * no memory is leaked.
1515+ */
1516+ template <typename U, typename T>
1517+ observable_sealed_ptr<U> dynamic_pointer_cast (observable_sealed_ptr<T>&& ptr) {
1518+ if (ptr == nullptr ) {
1519+ return observable_sealed_ptr<U>{};
1520+ }
1521+
1522+ U& casted_object = dynamic_cast <U&>(*ptr.get ());
1523+ return observable_sealed_ptr<U>(std::move (ptr), &casted_object);
1524+ }
1525+
1526+ // / Perform a `dynamic_cast` for an `observer_ptr`.
1527+ /* * \param ptr The pointer to cast
1528+ * \note A new observer is returned, the input observer is not modified.
1529+ If the input pointer is null, or if the cast fails, the output pointer
1530+ will be null.
1531+ */
1532+ template <typename U, typename T>
1533+ observer_ptr<U> dynamic_pointer_cast (const observer_ptr<T>& ptr) {
1534+ // NB: must use get() as dynamic cast of an expired pointer is UB
1535+ return observer_ptr<U>(ptr, dynamic_cast <U*>(ptr.get ()));
1536+ }
1537+
1538+ // / Perform a `dynamic_cast` for an `observer_ptr`.
1539+ /* * \param ptr The pointer to cast
1540+ * \note A new observer is returned, the input observer is set to null.
1541+ If the input pointer is null, or if the cast fails, the output pointer
1542+ will be null.
1543+ */
1544+ template <typename U, typename T>
1545+ observer_ptr<U> dynamic_pointer_cast (observer_ptr<T>&& ptr) {
1546+ // NB: must use get() as dynamic cast of an expired pointer is UB
1547+ return observer_ptr<U>(std::move (ptr), dynamic_cast <U*>(ptr.get ()));
1548+ }
1549+
13551550}
13561551
13571552#endif
0 commit comments