Avoid reinitializing nontrivial std::variant #76

When deserializing into an `std::variant<Ts...>` and the object we're
deserializing into already holds the requested variant, then we should
try to deserialize into the existing object instead of recreating it if
the variant is a nontrivial type. This is important when the object has
a default constructor that performs a nontrivial amount of work, or when
the object contains heap data that would need to be reallocated when
recreating the object.
This commit is contained in:
Robbert van der Helm
2021-05-28 14:55:59 +02:00
parent 47f6f9248a
commit d1830a263b

View File

@@ -54,6 +54,17 @@ namespace bitsery {
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem = typename std::variant_alternative<Index, std::variant<Ts...>>::type;
// Reinitializing nontrivial types may be expensive especially when they
// reference heap data, so if `data` is already holding the requested
// variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v<TElem>) {
if (auto item = std::get_if<TElem>(&data)) {
this->serializeType(des, *item);
return;
}
}
TElem item = ::bitsery::Access::create<TElem>();
this->serializeType(des, item);
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));