@@ -1527,21 +1527,27 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
15271527 }
15281528
15291529private:
1530+ // Implementation of copy-initialisation for value semantics.
15301531 void copy_init_from (const wrap &other)
15311532 {
15321533 static_assert (Cfg.semantics == wrap_semantics::value);
15331534
1534- if constexpr (Cfg.static_size == 0u ) {
1535- // Static storage disabled.
1536- this ->m_pv_iface = other.m_pv_iface ->_tanuki_clone_holder ();
1537- } else {
1538- if (other.stype ()) {
1539- // Other has static storage.
1540- this ->m_pv_iface = other.m_pv_iface ->_tanuki_copy_init_holder (this ->static_storage );
1541- } else {
1542- // Other has dynamic storage.
1535+ if (is_valid (other)) {
1536+ if constexpr (Cfg.static_size == 0u ) {
1537+ // Static storage disabled.
15431538 this ->m_pv_iface = other.m_pv_iface ->_tanuki_clone_holder ();
1539+ } else {
1540+ if (other.stype ()) {
1541+ // Other has static storage.
1542+ this ->m_pv_iface = other.m_pv_iface ->_tanuki_copy_init_holder (this ->static_storage );
1543+ } else {
1544+ // Other has dynamic storage.
1545+ this ->m_pv_iface = other.m_pv_iface ->_tanuki_clone_holder ();
1546+ }
15441547 }
1548+ } else {
1549+ // Handle initialisation from an invalid wrap.
1550+ this ->m_pv_iface = nullptr ;
15451551 }
15461552 }
15471553
@@ -1560,34 +1566,42 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
15601566 }
15611567
15621568private:
1569+ // Implementation of move-initialisation for value semantics.
1570+ //
15631571 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
15641572 void move_init_from (wrap &&other) noexcept
15651573 {
15661574 static_assert (Cfg.semantics == wrap_semantics::value);
15671575
1568- if constexpr (Cfg.static_size == 0u ) {
1569- // Static storage disabled. Shallow copy the pointer.
1570- this ->m_pv_iface = other.m_pv_iface ;
1571-
1572- // Invalidate other.
1573- other.m_pv_iface = nullptr ;
1574- } else {
1575- auto *pv_iface = other.m_pv_iface ;
1576-
1577- if (other.stype ()) {
1578- // Other has static storage.
1579- this ->m_pv_iface = std::move (*pv_iface)._tanuki_move_init_holder (this ->static_storage );
1580- } else {
1581- // Other has dynamic storage.
1582- this ->m_pv_iface = pv_iface;
1576+ if (is_valid (other)) {
1577+ if constexpr (Cfg.static_size == 0u ) {
1578+ // Static storage disabled. Shallow copy the pointer.
1579+ this ->m_pv_iface = other.m_pv_iface ;
15831580
15841581 // Invalidate other.
15851582 other.m_pv_iface = nullptr ;
1583+ } else {
1584+ auto *pv_iface = other.m_pv_iface ;
1585+
1586+ if (other.stype ()) {
1587+ // Other has static storage.
1588+ this ->m_pv_iface = std::move (*pv_iface)._tanuki_move_init_holder (this ->static_storage );
1589+ } else {
1590+ // Other has dynamic storage.
1591+ this ->m_pv_iface = pv_iface;
1592+
1593+ // Invalidate other.
1594+ other.m_pv_iface = nullptr ;
1595+ }
15861596 }
1597+ } else {
1598+ // Handle initialisation from an invalid wrap.
1599+ this ->m_pv_iface = nullptr ;
15871600 }
15881601 }
15891602
15901603public:
1604+ // Move constructor.
15911605 wrap (wrap &&other) noexcept
15921606 requires (Cfg.move_constructible || Cfg.semantics == wrap_semantics::reference)
15931607 && std::default_initializable<ref_iface_t >
@@ -1635,13 +1649,22 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
16351649 return *this ;
16361650 }
16371651
1638- // Handle invalid object .
1652+ // Handle invalid this .
16391653 if (is_invalid (*this )) {
16401654 // No need to destroy, just move-init from other is sufficient.
1655+ //
1656+ // NOTE: move_init_from() will work fine if other is invalid.
16411657 move_init_from (std::move (other));
16421658 return *this ;
16431659 }
16441660
1661+ // this is valid, handle invalid other.
1662+ if (is_invalid (other)) {
1663+ destroy ();
1664+ this ->m_pv_iface = nullptr ;
1665+ return *this ;
1666+ }
1667+
16451668 // Helper to implement move-assignment via destruction + move-initialisation.
16461669 const auto destroy_and_move_init = [this , &other]() noexcept {
16471670 destroy ();
@@ -1696,15 +1719,24 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
16961719 return *this ;
16971720 }
16981721
1699- // Handle invalid object .
1722+ // Handle invalid this .
17001723 if (is_invalid (*this )) {
17011724 // No need to destroy, just copy-init from other is sufficient.
17021725 //
17031726 // NOTE: copy_init_from() either succeeds or fails, no intermediate state is possible.
1727+ //
1728+ // NOTE: copy_init_from() will work fine if other is invalid.
17041729 copy_init_from (other);
17051730 return *this ;
17061731 }
17071732
1733+ // this is valid, handle invalid other.
1734+ if (is_invalid (other)) {
1735+ destroy ();
1736+ this ->m_pv_iface = nullptr ;
1737+ return *this ;
1738+ }
1739+
17081740 // NOTE: the idea here is as follows:
17091741 //
17101742 // - if the internal types are the same and copy-assignment is possible, employ it; otherwise,
@@ -1734,7 +1766,7 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
17341766 return *this ;
17351767 }
17361768
1737- // Assignment to the invalid state.
1769+ // Assignment from the invalid state.
17381770 wrap &operator =(invalid_wrap_t ) noexcept
17391771 {
17401772 if constexpr (Cfg.semantics == wrap_semantics::value) {
@@ -2036,7 +2068,12 @@ class TANUKI_VISIBLE wrap : private detail::wrap_storage<IFace, Cfg.static_size,
20362068 requires(Cfg.semantics == wrap_semantics::reference)
20372069 {
20382070 wrap retval (invalid_wrap);
2039- retval.m_pv_iface = w.m_pv_iface ->_tanuki_shared_clone_holder ();
2071+ // NOTE: perform the deep copy only if w is valid. Otherwise, return an invalid wrap.
2072+ if (is_valid (w)) {
2073+ retval.m_pv_iface = w.m_pv_iface ->_tanuki_shared_clone_holder ();
2074+ } else {
2075+ ;
2076+ }
20402077 return retval;
20412078 }
20422079
0 commit comments