@@ -299,6 +299,8 @@ struct enable_observer_from_this_base {
299299 // Friendship is required for assignment of the observer.
300300 template <typename U, typename P, typename ... Args>
301301 friend auto oup::make_observable (Args&&... args);
302+ template <typename U, typename D, typename P>
303+ friend class oup ::basic_observable_ptr;
302304};
303305} // namespace details
304306
@@ -415,23 +417,34 @@ class basic_observable_ptr final {
415417 /* *
416418 * \brief Decide whether to allocate a new control block or not.
417419 * \note If the object inherits from @ref basic_enable_observer_from_this, and
418- * `Policy::is_sealed` is false (by construction this will always be the case when this
419- * function is called), then we can just use the control block pointer stored in the
420- * @ref basic_enable_observer_from_this base. Otherwise, we need to allocate a new one.
420+ * the base @ref basic_enable_observer_from_this is guaranteed to have a valid block
421+ * pointer, then we can reuse this. Otherwise, we may need to allocate a new one.
421422 */
422423 template <typename U>
423- control_block_type* get_block_from_object_ (U* p) {
424+ control_block_type* get_or_create_block_from_object_ (U* p) noexcept (
425+ queries::eoft_always_has_block () && has_enable_observer_from_this<U, Policy>) {
426+
424427 if (p == nullptr ) {
425428 return nullptr ;
426429 }
427430
428- if constexpr (
429- queries::eoft_constructor_allocates () && has_enable_observer_from_this<U, Policy>) {
430- p->this_control_block ->push_ref ();
431- return p->this_control_block ;
431+ if constexpr (!has_enable_observer_from_this<U, Policy>) {
432+ return allocate_block_ ();
433+ } else {
434+ if constexpr (queries::eoft_always_has_block ()) {
435+ p->this_control_block ->push_ref ();
436+ return p->this_control_block ;
437+ } else {
438+ if (p->this_control_block != nullptr ) {
439+ p->this_control_block ->push_ref ();
440+ return p->this_control_block ;
441+ } else {
442+ control_block_type* new_block = allocate_block_ ();
443+ p->set_control_block_ (new_block);
444+ return new_block;
445+ }
446+ }
432447 }
433-
434- return allocate_block_ ();
435448 }
436449
437450 /* *
@@ -571,7 +584,8 @@ class basic_observable_ptr final {
571584 typename U,
572585 typename enable =
573586 std::enable_if_t <std::is_convertible_v<U*, T*> && queries::owner_allow_release()>>
574- explicit basic_observable_ptr (U* value) try :
587+ explicit basic_observable_ptr(U* value) noexcept (
588+ queries::eoft_always_has_block () && has_enable_observer_from_this<U, Policy>) try :
575589 basic_observable_ptr(get_or_create_block_from_object_(value), value) {
576590 } catch (...) {
577591 // Allocation of control block failed, delete input pointer and rethrow
@@ -592,7 +606,8 @@ class basic_observable_ptr final {
592606 typename U,
593607 typename enable =
594608 std::enable_if_t <std::is_convertible_v<U*, T*> && queries::owner_allow_release()>>
595- explicit basic_observable_ptr (U* value, Deleter del) try :
609+ explicit basic_observable_ptr (U* value, Deleter del) noexcept (
610+ queries::eoft_always_has_block () && has_enable_observer_from_this<U, Policy>) try :
596611 basic_observable_ptr(get_or_create_block_from_object_(value), value, std::move(del)) {
597612 } catch (...) {
598613 // Allocation of control block failed, delete input pointer and rethrow
@@ -687,19 +702,26 @@ class basic_observable_ptr final {
687702 typename U,
688703 typename enable =
689704 std::enable_if_t <std::is_convertible_v<U*, T*> && queries::owner_allow_release()>>
690- void reset (U* ptr) {
705+ void reset (U* ptr) noexcept (
706+ queries::eoft_always_has_block () && has_enable_observer_from_this<U, Policy>) {
691707 // Copy old pointer
692708 T* old_ptr = ptr_deleter.data ;
693709 control_block_type* old_block = block;
694710
695711 // Assign the new one
696- try {
712+ if constexpr (noexcept (get_or_create_block_from_object_ (ptr))) {
713+ // There is always a control block available for us, so this cannot fail
697714 block = get_or_create_block_from_object_ (ptr);
698715 ptr_deleter.data = ptr;
699- } catch (...) {
700- // Allocation of control block failed, delete input pointer and rethrow
701- ptr_deleter (ptr);
702- throw ;
716+ } else {
717+ try {
718+ block = get_or_create_block_from_object_ (ptr);
719+ ptr_deleter.data = ptr;
720+ } catch (...) {
721+ // Allocation of control block failed, delete input pointer and rethrow
722+ ptr_deleter (ptr);
723+ throw ;
724+ }
703725 }
704726
705727 // Delete the old pointer
0 commit comments