@@ -258,7 +258,11 @@ class observable_unique_ptr_base {
258
258
*/
259
259
template <typename U, typename D>
260
260
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
+
262
266
manager.block = nullptr ;
263
267
manager.ptr_deleter .data = nullptr ;
264
268
}
@@ -272,7 +276,11 @@ class observable_unique_ptr_base {
272
276
*/
273
277
template <typename U, typename D>
274
278
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
+
276
284
manager.block = nullptr ;
277
285
manager.ptr_deleter .data = nullptr ;
278
286
}
@@ -520,7 +528,10 @@ class observable_unique_ptr :
520
528
* \param value The casted pointer value to take ownership of
521
529
* \note After this observable_unique_ptr is created, the source
522
530
* 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`.
524
535
*/
525
536
template <typename U, typename D, typename V, typename enable =
526
537
std::enable_if_t <std::is_convertible_v<V*,T*>>>
@@ -534,7 +545,10 @@ class observable_unique_ptr :
534
545
* \param value The casted pointer value to take ownership of
535
546
* \param del The deleter to use in the new pointer
536
547
* \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`.
538
552
*/
539
553
template <typename U, typename D, typename V, typename enable =
540
554
std::enable_if_t <std::is_convertible_v<V*,T*>>>
@@ -728,10 +742,14 @@ class observable_sealed_ptr :
728
742
/* * \param manager The smart pointer to take ownership from
729
743
* \param value The casted pointer value to take ownership of
730
744
* \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`.
732
749
*/
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 :
735
753
base (std::move(manager), value) {}
736
754
737
755
// / Transfer ownership by implicit casting
@@ -996,6 +1014,24 @@ class observer_ptr {
996
1014
}
997
1015
}
998
1016
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
+
999
1035
// / Move from an existing `observer_ptr` instance
1000
1036
/* * \param value The existing observer pointer to move from
1001
1037
* \note After this `observer_ptr` is created, the source
@@ -1018,6 +1054,27 @@ class observer_ptr {
1018
1054
value.data = nullptr ;
1019
1055
}
1020
1056
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
+
1021
1078
// / Point to another owning pointer.
1022
1079
/* * \param owner The new owner pointer to observe
1023
1080
* \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
1320
1377
};
1321
1378
1322
1379
public:
1323
-
1324
- using observer_element_type = T;
1325
-
1326
1380
// / Return an observer pointer to 'this'.
1327
1381
/* * \return A new observer pointer pointing to 'this'.
1328
1382
* \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
1352
1406
}
1353
1407
};
1354
1408
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
+
1355
1550
}
1356
1551
1357
1552
#endif
0 commit comments