From d1830a263b17f34e90759760a888ee83f969d85b Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 28 May 2021 14:55:59 +0200 Subject: [PATCH] Avoid reinitializing nontrivial std::variant #76 When deserializing into an `std::variant` 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. --- include/bitsery/ext/std_variant.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/bitsery/ext/std_variant.h b/include/bitsery/ext/std_variant.h index f5dd17f..2834c34 100644 --- a/include/bitsery/ext/std_variant.h +++ b/include/bitsery/ext/std_variant.h @@ -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>::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) { + if (auto item = std::get_if(&data)) { + this->serializeType(des, *item); + return; + } + } + TElem item = ::bitsery::Access::create(); this->serializeType(des, item); data = std::variant(std::in_place_index_t{}, std::move(item));