Further improve sorted_vector_types standard compliance
Summary: This is a follow up from D16427231; after testing the code in a similar situation on a mac (with `clang` and `libc++`) I realized there were still standards compliance issues. In that diff, the guarantee we provide is: ``` * - insert() single key variants, emplace(), and emplace_hint() only provide * the strong exception guarantee (unchanged when exception is thrown) when * std::is_nothrow_move_constructible<value_type>::value is true. ``` The implementation is eventually backed by `std::vector`. The guarantees provided by `std::vector` in the standard are slightly weaker (https://en.cppreference.com/w/cpp/container/vector/insert): ``` If an exception is thrown when inserting a single element at the end, and T is CopyInsertable or std::is_nothrow_move_constructible<T>::value is true, there are no effects (strong exception guarantee). ``` i.e. it only provides this safety guarantee if the element is inserted at the end, and that's exactly what the new test shows. After discussion with nbronson we discovered that `libstdc++` and `libc++` are using different techniques to handle the corner case of `v.insert(0, v[1])` for `insert(iter, value_type const&)`. `libstdc++` makes the copy into a temporary, and then moves it in, so it does in fact provide a stronger guarantee than necessary. `libc++` checks the address of the reference it is given, and if it is in the moved range it adjusts it (!) and then uses the copy assignment operator. This means on copy assignment exception there will be a moved-from element at the desired index. Section 26.2.1 para 11 says that `insert` or `emplace` will have no effects if an exception is thrown, unless otherwise specified. 26.3.11.5 is the `vector` modifiers, but that only mentions `insert`. That means we can fix this by merely switch our uses of `std::vector::insert` to `std::vector::emplace` inside `sorted_vector_map/set`. On `libstdc++` this should't have any effect, since both insert and emplace make a temporary copy for the non-end insertion case (in different but similar code paths). On `libc++` this will avoid the address-adjusting trick and use the temporary copy technique like in `libstdc++`. Reviewed By: yfeldblum Differential Revision: D20785383 fbshipit-source-id: 290c3c7c061dedf1660da9534f4b9cc338da6224
Showing
Please register or sign in to comment