7 votes

Pourquoi `std::pmr::polymorphic_allocator` ne se propage pas lors du déplacement du conteneur ?

En http://en.cppreference.com/w/cpp/memory/polymorphic_allocator :

polymorphic_allocator ne se propage pas lors d'une affectation de copie de conteneur, d'une affectation de déplacement ou d'un échange. Par conséquent, l'affectation de déplacement d'un polymorphic_allocator -utilisation d'un conteneur peut jeter, et l'échange de deux polymorphic_allocator -L'utilisation de conteneurs dont les allocateurs ne se comparent pas de manière égale entraîne un comportement non défini.

Pourquoi voudrais-je avoir ce comportement ? Non seulement cela semble introduire un comportement indéfini gratuit sur le swap, mais plus important encore pour mes objectifs, cela implique que std::pmr::vector est effectivement un type non assignable par le mouvement. Je veux dire, il est assignable par le mouvement, mais c'est presque garanti d'être inefficace.

std::vector<int> v = {1, 2, 3};
std::vector<int> w;
w = std::move(v);  // nocopy, nothrow

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w;
w = std::move(v);  // yescopy, yesthrow

Je pense qu'il s'agit d'une tentative primitive de régler les problèmes de propriété. Dans mon deuxième exemple ci-dessus, v contient une référence à mr mais v n'a pas réellement propre mr . Permettre aux références non propriétaires de se propager sans contrôle dans tout le système aurait tendance à introduire de nombreux bogues subtils. Ainsi, plutôt que d'inventer un posséder les concepteurs ont décidé de simplement ne pas propager la référence à mr . Cela a fini par avoir de mauvais effets, comme le fait que le déplacement d'un vecteur copie maintenant ses données ; mais vous ne vous retrouvez pas avec autant de pointeurs pendants vers des ressources mémoire. ( Quelques Oui, mais pas autant .)


P.S. Je vois déjà que vous pouvez éviter le copier/jeter en configurant l'allocateur à l'avance, comme ceci :

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w(v.get_allocator());
w = std::move(v);  // nocopy, nothrow

7voto

Nicol Bolas Points 133791

En allocator_traits<>::propagate_on_container_copy/move_assignment/swap sont statique les propriétés d'un allocateur. Un allocateur polymorphe, par conception, a ses propriétés définies à temps de fonctionnement . Certains allocateurs polymorphes peuvent se propager à d'autres, et d'autres non.

Il est donc impossible que ces propriétés soient connues au moment de la compilation. L'allocateur PMR doit donc supposez le pire cas au moment de la compilation : pas de propagation.

Prenons votre exemple, avec une modification :

std::pmr::monotonic_buffer_resource mr(1000);
std::pmr::vector<int> v( {1, 2, 3}, &mr );
std::pmr::vector<int> w;
auto a1 = w.get_allocator();
w = std::move(v);
assert(w.get_allocator() == a1);

La norme C++ nécessite que cela n'affirme pas. L'affectation ne déplace pas le allocateur d'un conteneur ; c'est ainsi que l'affectation des conteneurs fonctionne avec les allocateurs en C++.

Par conséquent, soit l'allocateur du conteneur de destination peut gérer la mémoire du conteneur source, soit il ne le peut pas. Et s'il ne peut pas, alors le conteneur de destination doit allouer de la mémoire et copier/déplacer les objets depuis la source.

Si l'opérateur d'affectation de déplacement est noexcept ou non est une propriété statique de l'opérateur. Et comme les PMR ne peuvent pas savoir avant l'exécution s'ils peuvent propager le stockage, le conteneur doit désigner son opérateur d'affectation de mouvement comme une affectation de mouvement de lancement.

Au moment de l'exécution, il peut en fait décider si la propagation est possible ou non. Et si c'est possible, il prendra le chemin le plus efficace.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X