Déplacer qui jette?

À ma connaissance, move-constructors et move-assign doivent être marqués noexcept pour que le compilateur puisse les utiliser lors, par exemple, d’une réaffectation dans un vecteur.

Cependant, y a-t-il un cas réel où une construction-assignation, une construction-déménagement pourrait réellement lancer?

Mise à jour :

Les classes qui, par exemple, ont une ressource allouée lorsqu’elles sont construites ne peuvent pas être déplacées sans projection.

Cependant, existe-t-il un cas réel où un déplacement-assign, une construction-déménagement (ou swap) pourrait réellement lancer?

Oui. Considérons une implémentation de std::list . L’iterator end doit pointer “un dernier dernier élément” dans la liste. Il existe des implémentations de std::list où l’ end désigne un nœud alloué dynamicment. Même le constructeur par défaut alloue un tel nœud de sorte que lorsque vous appelez end() , il y a quelque chose à pointer.

Dans une telle implémentation, chaque constructeur doit allouer un noeud pour que end() pointe vers… même le constructeur du déplacement. Cette allocation peut échouer et lever une exception.

Ce même comportement peut s’étendre à tout conteneur basé sur un nœud.

Il existe également des implémentations de ces conteneurs basés sur des nœuds qui effectuent une optimisation “chaîne courte”: ils intègrent le nœud d’extrémité dans la classe de conteneur elle-même, au lieu d’une allocation dynamic. Ainsi, le constructeur par défaut (et le constructeur de mouvements) n’a rien à allouer.

L’opérateur d’affectation de mouvement peut lancer n’importe quel container si la valeur de l’allocateur du conteneur est propagate_on_container_move_assignment::value false, et si l’allocateur dans le lhs n’est pas égal à l’allocateur dans le rhs. Dans ce cas, il est interdit à l’opérateur d’atsortingbution de déplacement de transférer la propriété de la mémoire du rhs au lhs. Cela ne peut pas arriver si vous utilisez std::allocator , car toutes les instances de std::allocator sont égales les unes aux autres.

Mettre à jour

Voici un exemple conforme et portable du cas où propagate_on_container_move_assignment::value est false. Il a été testé sur la dernière version de VS, gcc et clang.

 #include  #include  #include  #include  template  class allocator { int id_; public: using value_type = T; allocator(int id) noexcept : id_(id) {} template  allocator(allocator const& u) noexcept : id_(u.id_) {} value_type* allocate(std::size_t n) { return static_cast(::operator new (n*sizeof(value_type))); } void deallocate(value_type* p, std::size_t) noexcept { ::operator delete(p); } template  friend bool operator==(allocator const& x, allocator const& y) noexcept { return x.id_ == y.id_; } }; template  bool operator!=(allocator const& x, allocator const& y) noexcept { return !(x == y); } template  using vector = std::vector>; struct A { static bool time_to_throw; A() = default; A(const A&) {if (time_to_throw) throw 1;} A& operator=(const A&) {if (time_to_throw) throw 1; return *this;} }; bool A::time_to_throw = false; int main() { vector v1(5, A{}, allocator{1}); vector v2(allocator{2}); v2 = std::move(v1); try { A::time_to_throw = true; v1 = std::move(v2); assert(false); } catch (int i) { std::cout << i << '\n'; } } 

Ce programme génère:

 1 

ce qui indique que le vector , l'opérateur d'affectation de déplacement, copie / déplace ses éléments lorsque propagate_on_container_move_assignment::value est défini sur false et que les deux allocateurs en question ne se comparent pas égaux. Si l'un de ces copies / déplacements est lancé, l'affectation de déplacement de conteneur est levée.

Oui, les constructeurs de mouvements de lancer existent dans la nature. Considérons std::pairT peut pas être déplacé, et U est uniquement copiable (supposons que des copies puissent être jetées). Ensuite, vous avez un constructeur de mouvements std::pair utile qui peut lancer.

Si vous avez besoin d’un utilitaire std::move_if_noexcept dans la bibliothèque standard (utile pour implémenter std::vector::resize avec au moins la garantie d’exception de base).

Voir aussi Move constructors et la garantie d’exception forte

Déplacer des constructeurs sur des classes avec des membres de données const peut également lancer. Vérifiez ici pour plus d’informations.