C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Way to get rid of valueless_by_exception in std::variant

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Tue, 28 Oct 2025 14:11:14 +0100
In those cases the classes are not trivially movable (otherwise no exception). and the move constructor may need to do special operations for each move. E.g. notify the hardware not to store a status flag at the memory address within the object. Or store the status flag at a different address.   -----Ursprüngliche Nachricht----- Von:Nikl Kelbon via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Di 28.10.2025 14:17 Betreff:Re: [std-proposals] Way to get rid of valueless_by_exception in std::variant An:std-proposals_at_[hidden]; CC:Nikl Kelbon <kelbonage_at_[hidden]>; We talk about movable types, in cases when move constructor may throw exception вт, 28 окт. 2025 г. в 18:12, Sebastian Wittmeier via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> >: No, the memory can be used to communicate with the hardware or special flags (e.g. non-pageable) were assigned with the help of the operating system. The standard library should not move non-moveable arbitrary objects around.   I have not even started talking about multi-threaded use.   -----Ursprüngliche Nachricht----- Von:Nikl Kelbon via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> > Gesendet:Di 28.10.2025 13:48 Betreff:Re: [std-proposals] Way to get rid of valueless_by_exception in std::variant An:std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> ; CC:Nikl Kelbon <kelbonage_at_[hidden] <mailto:kelbonage_at_[hidden]> >; > Again, this is potentially undefined behaviour. Thats why it must be in standard library, others cannot do it without UB About memcpy, it seems for you, that its not correct, because you're used to the fact that it's wrong. But if you memswap ANY type twice into buffer and into original place again any type, even self reference, will work. Its impossible to break something with such memory manipulations вт, 28 окт. 2025 г. в 17:23, Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> >: On Tue, Oct 28, 2025 at 12:16 PM Frederick Virchanza Gotham wrote: > > Here's code I shared earlier in the week on this mailing list: > >     https://godbolt.org/z/nbeKMKe1o Sorry, disregard my last post, as it only constructs another T in the place of an original T. The following code allows the construction of a different type in place of the original T:    https://godbolt.org/z/oPKb977qb    (Of course it assumes that the memory alignment is correct) And here it is copy-pasted: #include <cassert>      // assert #include <cstddef>      // byte #include <cstring>      // memcpy #include <algorithm>    // swap_ranges #include <memory>       // construct_at, destroy_at #include <type_traits>  // type traits #include <utility>      // forward, move #ifdef NDEBUG #    define CRASH_IN_DEBUG_MODE()    /* nothing */ #else #    define CRASH_IN_DEBUG_MODE()    assert(nullptr == "Destructor threw an exception!") #endif #if defined(HAS_STD_RELOCATE_AT) && defined(HAS_STD_IS_NOTHROW_RELOCATABLE) #    define CAN_USE_STD_RELOCATE 1 #else #    define CAN_USE_STD_RELOCATE 0 #endif template<typename T, typename U = T, typename... Args> requires (!std::is_const_v<T> && !std::is_volatile_v<T>) void replace(T *const where, Args&&... args) noexcept(std::is_nothrow_constructible_v<U, Args...>) {     using std::construct_at;     using std::destroy_at;     if constexpr ( std::is_nothrow_constructible_v<U, Args...> )     {         try { destroy_at(where); } catch (...) { CRASH_IN_DEBUG_MODE(); }         construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...);     } #if CAN_USE_STD_RELOCATE     else if constexpr ( true )     {         alignas(T) std::byte elsewhere[sizeof(T)];         T *const elsewhereT = static_cast<T*>(static_cast<void*>(elsewhere));         // Relocation is supported (non-standard extension)         if constexpr ( std::is_nothrow_relocatable_v<T> )         {             std::relocate_at(where, elsewhereT);             try { construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...); }             catch (...)             {                 std::relocate_at(elsewhereT, where);                 throw;             }             try { destroy_at(elsewhereT); } catch (...) { CRASH_IN_DEBUG_MODE(); }         }         else if constexpr ( std::is_nothrow_move_constructible_v<T> )         {             // Relocation exists but isn't noexcept — fallback to move             construct_at(elsewhereT, std::move(*where));             try { destroy_at(where); } catch (...) { CRASH_IN_DEBUG_MODE(); }             try { construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...); }             catch (...)             {                 construct_at(where, std::move(*elsewhereT));                 try { destroy_at(elsewhereT); } catch (...) { CRASH_IN_DEBUG_MODE(); }                 throw;             }             try { destroy_at(elsewhereT); } catch (...) { CRASH_IN_DEBUG_MODE(); }         }         else         {             static_assert( false == requires { typename T::tag_never_retain; } );             using std::memcpy;             std::byte elsewhere[sizeof(T)];             memcpy(elsewhere, where, sizeof *elsewhere);             try { construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...); }             catch (...)             {                 memcpy(where, elsewhere, sizeof *where);                 throw;             }             std::swap_ranges(                 elsewhere,                 elsewhere + sizeof elsewhere,                 static_cast<std::byte*>(static_cast<void*>(where))             );             try { destroy_at(where); } catch (...) { CRASH_IN_DEBUG_MODE(); }             memcpy(where, elsewhere, sizeof *where);         }     } #endif // if CAN_USE_STD_RELOCATE     else if constexpr (std::is_nothrow_move_constructible_v<T>)     {         // No relocation support; fallback to move construction         alignas(T) std::byte elsewhere[sizeof(T)];         T *const elsewhereT = static_cast<T*>(static_cast<void*>(elsewhere));         construct_at(elsewhereT, std::move(*where));         try { destroy_at(where); } catch (...) { CRASH_IN_DEBUG_MODE(); }         try { construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...); }         catch (...)         {             construct_at(where, std::move(*elsewhereT));             try { destroy_at(elsewhereT); } catch (...) { CRASH_IN_DEBUG_MODE(); }             throw;         }         try { destroy_at(elsewhereT); } catch (...) { CRASH_IN_DEBUG_MODE(); }     }     else     {         static_assert( false == requires { typename T::tag_never_retain; } );         using std::memcpy;         std::byte elsewhere[sizeof(T)];         memcpy(elsewhere, where, sizeof *elsewhere);         try { construct_at(reinterpret_cast<U*>(where), std::forward<Args>(args)...); }         catch (...)         {             memcpy(where, elsewhere, sizeof *where);             throw;         }         std::swap_ranges(             elsewhere,             elsewhere + sizeof elsewhere,             static_cast<std::byte*>(static_cast<void*>(where))         );         try { destroy_at(where); } catch (...) { CRASH_IN_DEBUG_MODE(); }         memcpy(where, elsewhere, sizeof *where);     } } #include <string> int main(void) {     struct Monkey {         Monkey(void) noexcept(false) = default;         Monkey(Monkey&) = delete;         Monkey(Monkey&&) = delete;         typedef int tag_never_retain2;   // try removing the '2' here     };     Monkey var;     replace(&var);     std::string str;     replace(&str);     replace<std::string,Monkey>(&str); } -- Std-Proposals mailing list Std-Proposals_at_[hidden] <mailto:Std-Proposals_at_[hidden]> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals -- Std-Proposals mailing list Std-Proposals_at_[hidden] <mailto:Std-Proposals_at_[hidden]> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals -- Std-Proposals mailing list Std-Proposals_at_[hidden] <mailto:Std-Proposals_at_[hidden]> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2025-10-28 13:24:26