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 13:59:12 +0100
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]> 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]; CC:Nikl Kelbon <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] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2025-10-28 13:12:25