What is the reason for having these traits in a container (https://en.cppreference.com/w/cpp/memory/allocator_traits)
propagate_on_container_copy_assignment Alloc::propagate_on_container_copy_assignment if present, otherwise std::false_type
propagate_on_container_move_assignment Alloc::propagate_on_container_move_assignment if present, otherwise std::false_type
propagate_on_container_swap Alloc::propagate_on_container_swap if present, otherwise std::false_type
is_always_equal(since C++17) Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
I understand that the container implementation will behave in one way or another in their implementation of assignment and swap. (and that handling of these case is horrible code.) I also understand that sometimes one might need to leave the move-from container in a state that is resizeble or that at least some very last deallocation can be called, so the allocator can't be left invalid. (I personally think that is a weak argument.)
But the question is, Why can't that information be already part of the normal implementation an semantics of the custom allocator type itself?
I mean, container copy-assignment can try copy-assign the source allocator, and if that syntactic copy assign doesn't really copy, then, well, it is like saying that your container doesn't propagate_on_container_copy_assignment.
In the same way instead of using is_always_equal one can actually make the allocator assignment do nothing.
(Besides, if is_always_equal is true one can make operator== for allocators return std::true_type to signal that.)
It looks to me that these traits seem to try override the semantics that one can give to the custom allocator by normal C++ means. This seems to play against generic programming and the current C++ philosophy.
The only reason, I can think of this can be useful to fulfill some kind of backward compatibility with "old" containers.
If I were to write a new container and/or an new non-trivial allocator today, can I rely on the sematics of the allocator and forget about these traits?
In my view, as long as the moved-from allocator can "deallocate" a null pointer state (which means mostly to do nothing in this case), then it should be fine, and if resize throws that is fine (valid) too, it simply means that the allocator doesn't have access to its heap anymore.
Aucun commentaire:
Enregistrer un commentaire