Which of the move-assignment, copy-assignment, and swap operations (if any) also operate on the embedded comparators for sets and maps?
(In other words, if I e.g. swap
two set
s, will their comparators be swapped too, or no?)
If the answer is different for older versions of C++ (e.g. C++98 or C++03) then please mention that.
This is LWG 2227, still open for now.
The current standard is still not very clear on the related requirements.
Swapping is relatively simple. Major implementations (libstdc++, libc++ and Microsoft's STL) all swap the comparison object in swap
. This is also consistent on the other wording suggesting the comparsion object should be swapped.
Major implementations still diverge on moving. As I've checked today, the current implementation of libstdc++ and Microsoft's STL both copy the comparison object in the move constructor of the underlying tree/hash table, but libc++ just moves it respectively. Note the situation has changed on MS's implmetation comparing to the comment in 2015.
The copy constructible requirement on comparison objects/hashers/predicates are clearly not gone, though. That is, you may assume it is still like C++ 98/03 era where there is no move at all.
Logically libstdc++/MS STL's behavior is simpler. Comparison objects behave like iterators or normal function objects (but not functions passed in forwarding call wrappers): expected passed by value and no identity on those objects can be clearly implied. And this is logically consistent to the old world without moving.
However, for implementations moving respectively can be simpler a bit, by reusing the moving operations of some EBO helper objects (e.g. __compressed_pair
in libc++) with defaulted special member functions instead of user-defined copying (without moving). Such implementations may need some additional care on the exception specifications, but the complexity is already there to support allocator propagation on these allocator-aware containers.
Nevertheless, stateful comparison objects (and hashers/predicates) just do not get first-class support in C++ containers. And sadly, it is not obvious how they can be supported without messing up the ownership management in the client code, because users need to save the state elsewhere and these states are not naturally (uniquely) owned by the container object, esp. when considering the opposite case by just adding some std::ref
. This is no more worse than stateful allocators (which incur another dimension of complexicity like fined-grained control of allocator propagation and UB on swap
ping unqual allocators in container objects), though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With