[PATCH] PR libstdc++/87431 re-adjust never-valueless optimizations
Jonathan Wakely
jwakely@redhat.com
Wed Apr 3 16:25:00 GMT 2019
Avoid creating arbitrarily large objects on the stack when creating
temporaries in order to provide the strong exception-safety guarantee.
Also implement Antony Polukhin's suggestion to whitelist specific types
that can be efficiently move-assigned, so that emplacing those types
never causes a variant to become valueless. The whitelisted types are:
all trivially copyable types no greater than 256 bytes in size,
std::shared_ptr, std::weak_ptr, std::unique_ptr, std::function, and
std::any. Additionally, std::basic_string, std::vector, and
__gnu_debug::vector are whitelisted if their allocator traits give them
a non-throwing move assignment operator. Specifically, this means
std::string is whitelisted, but std::pmr::string is not.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
I'd like to commit this to trunk this week. Does anybody see any
problems with this approach?
As the comment in <variant> says, the _Never_valueless_alt trait has
ABI impact, so we should define it for more types now, or not at all.
When we add new types to the library we should consider if they need a
specialization of _Never_valueless_alt.
Should we also whitelist some (all?) other containers, as they all
have conditionally noexcept move assignment operators, and those
assignments are efficient when noexcept (because they don't
reallocate). Are there other types in the library we should consider
it for?
std::optional<T> is automatically whitelisted for trivially copyable
types, because if T is trivially copyable then optional<T> should be
too. We could also whitelist other specializations though:
template<typename T>
struct _Never_valueless_alt<optional<T>>
: _Never_valueless_alt<T>
{ };
We could also do:
template<typename T, typename U>
struct _Never_valueless_alt<pair<T, U>>
: __and_<_Never_valueless_alt<T>, _Never_valueless_alt<U>>
{ };
template<typename... T>
struct _Never_valueless_alt<tuple<T...>>
: __and_<_Never_valueless_alt<T>...>
{ };
In case it isn't clear, under normal circumstances something like a
variant<pair<int,int>,int> won't ever become valueless anyway, because
initialization of those alternatives doesn't throw. But what can throw
is a conversion operator that is invoked to produce one of those
alternatives. The _Never_valueless_alt trait says that emplacing an
alternative of that type should do some extra work to ensure the
variant doesn't become valueless *ever*. And then a variant that only
has never-valueless alternatives is itself never-valueless, and so the
valueless_by_exception() member just returns false, and visitation is
more efficient as it doesn't need to deal with the valueless state.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch.txt
Type: text/x-patch
Size: 21852 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20190403/27672c1a/attachment.bin>
More information about the Libstdc++
mailing list