mirror of
https://github.com/ETLCPP/etl.git
synced 2026-07-30 16:26:17 +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()
|
||||
{
|
||||
do_destroy_impl(etl::integral_constant<bool, Is_Trivially_Destructible_Suite>{});
|
||||
|
||||
type_id = variant_npos;
|
||||
}
|
||||
|
||||
void do_destroy_impl(etl::integral_constant<bool, true>)
|
||||
|
||||
@ -1097,6 +1097,71 @@ namespace
|
||||
}
|
||||
#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)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user