mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Fix variant emplace to be valueless after a throwing construction (#1510)
variant::do_destroy() now always resets type_id to variant_npos after destroying the active alternative. emplace()/operator= set the new discriminator only after successful construction, so if the constructor throws the variant is left valueless (index() == variant_npos) instead of reporting the stale old index. Add regression test test_emplace_throwing_is_valueless_by_exception covering both the trivially-destructible (union) and non-trivially- destructible (buffer) storage suites. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
08b9c371a0
commit
a74c33bab9
@ -1400,6 +1400,8 @@ namespace etl
|
|||||||
void do_destroy()
|
void do_destroy()
|
||||||
{
|
{
|
||||||
do_destroy_impl(etl::integral_constant<bool, Is_Trivially_Destructible_Suite>{});
|
do_destroy_impl(etl::integral_constant<bool, Is_Trivially_Destructible_Suite>{});
|
||||||
|
|
||||||
|
type_id = variant_npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_destroy_impl(etl::integral_constant<bool, true>)
|
void do_destroy_impl(etl::integral_constant<bool, true>)
|
||||||
|
|||||||
@ -1097,6 +1097,71 @@ namespace
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ETL_USING_EXCEPTIONS
|
||||||
|
//*************************************************************************
|
||||||
|
// A throwing emplace() must leave the variant valueless-after-exception
|
||||||
|
// (index() == variant_npos) rather than reporting the stale old index.
|
||||||
|
struct ThrowOnConstruct
|
||||||
|
{
|
||||||
|
struct exception
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
ThrowOnConstruct() = default;
|
||||||
|
explicit ThrowOnConstruct(int)
|
||||||
|
{
|
||||||
|
throw exception();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(test_emplace_throwing_is_valueless_by_exception)
|
||||||
|
{
|
||||||
|
// Trivially destructible suite (variadic_union storage).
|
||||||
|
{
|
||||||
|
etl::variant<int, ThrowOnConstruct> v;
|
||||||
|
v.emplace<int>(42);
|
||||||
|
CHECK(!v.valueless_by_exception());
|
||||||
|
CHECK_EQUAL(0U, v.index());
|
||||||
|
|
||||||
|
bool threw = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
v.emplace<ThrowOnConstruct>(1);
|
||||||
|
}
|
||||||
|
catch (const ThrowOnConstruct::exception&)
|
||||||
|
{
|
||||||
|
threw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(threw);
|
||||||
|
CHECK(v.valueless_by_exception());
|
||||||
|
CHECK_EQUAL(etl::variant_npos, v.index());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-trivially destructible suite (uninitialized_buffer storage).
|
||||||
|
{
|
||||||
|
etl::variant<std::string, ThrowOnConstruct> v;
|
||||||
|
v.emplace<std::string>("Some Text");
|
||||||
|
CHECK(!v.valueless_by_exception());
|
||||||
|
CHECK_EQUAL(0U, v.index());
|
||||||
|
|
||||||
|
bool threw = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
v.emplace<1>(1);
|
||||||
|
}
|
||||||
|
catch (const ThrowOnConstruct::exception&)
|
||||||
|
{
|
||||||
|
threw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(threw);
|
||||||
|
CHECK(v.valueless_by_exception());
|
||||||
|
CHECK_EQUAL(etl::variant_npos, v.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
TEST(test_copy_constructor)
|
TEST(test_copy_constructor)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user