From 30d974d0fc447b627cf29d50268136d1d6460ff3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 26 Feb 2019 15:12:37 +0200 Subject: [PATCH] Fix exception safety issue in copy/move/converting constructor --- include/boost/variant2/variant.hpp | 36 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index b0f759f..de9b8d3 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -608,6 +608,13 @@ template struct variant_base_impl { } + // requires: ix_ == 0 + template void _replace( I, A&&... a ) + { + ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = I::value + 1; + } + constexpr std::size_t index() const noexcept { return ix_ - 1; @@ -700,6 +707,13 @@ template struct variant_base_impl { } + // requires: ix_ == 0 + template void _replace( I, A&&... a ) + { + ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = I::value + 1; + } + constexpr std::size_t index() const noexcept { return ix_ >= 0? ix_ - 1: -ix_ - 1; @@ -755,6 +769,13 @@ template struct variant_base_impl { } + // requires: ix_ == 0 + template void _replace( I, A&&... a ) + { + ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = I::value + 1; + } + //[&]( auto I ){ // using U = mp_at_c, I>; // st1_.get( I ).~U(); @@ -869,6 +890,13 @@ template struct variant_base_impl { } + // requires: ix_ == 0 + template void _replace( I, A&&... a ) + { + ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = I::value + 1; + } + //[&]( auto I ){ // using U = mp_at_c, I>; // st1_.get( I ).~U(); @@ -1090,7 +1118,7 @@ private: template void operator()( I i ) const { - ::new( static_cast( this_ ) ) variant_base( i, r._get_impl( i ) ); + this_->_replace( i, r._get_impl( i ) ); } }; @@ -1123,7 +1151,7 @@ private: template void operator()( I i ) const { - ::new( static_cast( this_ ) ) variant_base( i, std::move( r._get_impl( i ) ) ); + this_->_replace( i, std::move( r._get_impl( i ) ) ); } }; @@ -1369,7 +1397,7 @@ private: template void operator()( I i ) const { using J = mp11::mp_find, mp11::mp_at, I>>; - ::new( static_cast(this_) ) variant_base( J{}, r._get_impl( i ) ); + this_->_replace( J{}, r._get_impl( i ) ); } }; @@ -1393,7 +1421,7 @@ private: template void operator()( I i ) const { using J = mp11::mp_find, mp11::mp_at, I>>; - ::new( static_cast(this_) ) variant_base( J{}, std::move( r._get_impl( i ) ) ); + this_->_replace( J{}, std::move( r._get_impl( i ) ) ); } };