问题
In an answer to this SO question:
What is the equivalent of boost::variant in the C++ standard library?
it is mentioned that boost::variant and std::variant differ somewhat.
- What are the differences, as far as someone using these classes is concerned?
- What motivation did the committee express to adopt
std::variantwith these differences? - What should I watch out for when coding with either of these, to maintain maximum compatibility with switching to the other one?
(the motivation is using boost::variant in pre-C++17 code)
回答1:
Assignment/emplacement behavior:
boost::variantmay allocate memory when performing assignment into a livevariant. There are a number of rules that govern when this can happen, so whether aboost::variantwill allocate memory depends on theTsit is instantiated with.std::variantwill never dynamically allocate memory. However, as a concession to the complex rules of C++ objects, if an assignment/emplacement throws, then thevariantmay enter the "valueless_by_exception" state. In this state, thevariantcannot be visited, nor will any of the other functions for accessing a specific member work.You can only enter this state if assignment/emplacement throws.
Boost.Variant includes
recursive_variant, which allows a variant to contain itself. They're essentially special wrappers around a pointer to aboost::variant, but they are tied into the visitation machinery.std::varianthas no such helper type.std::variantoffers more use of post-C++11 features. For example:It forwards the
noexceptstatus of the special member functions of its constituent types.It has variadic template-based in-place constructors and emplacement functions.
Defect resolutions applied to C++17 may mean that it will also forward trivial copyability of its types. That is, if all of the types are trivially copyable, then so too will
variant<Ts>.
回答2:
It seems the main point of contention regarding the design of a variant class has been what should happen when an assignment to the variant, which should upon completion destory the old value, throws an exception:
variant<std::string, MyClassWithThrowingDefaultCtor> v = "ABC";
v = MyClassWithThrowingDefaultCtor();
The options seem to be:
- Prevent this by restricting the possible representable types to nothrow-move-constructible ones.
- Keep the old value - but this requires double-buffers (which is what
boost::variantdoes apparently). - Have a 'disengaged' state with no value for each variant, and go to that state on such failures.
- Undefined behavior
- Make the variant throw when trying to read its value after something like that happens
and if I'm not mistaken, the latter is what's been accepted.
This is summarized from the ISO C++ blog post by Axel Naumann from Nov 2015.
来源:https://stackoverflow.com/questions/40201371/what-are-the-differences-between-stdvariant-and-boostvariant