Insérer dans un vecteur ayant des objects sans constructeur de copie

J’ai une classe dont les constructeurs de copie sont explicitement supprimés (parce que A utilise des pointeurs en interne et que je ne veux pas tomber dans les pièges de copie superficielle):

class A { public: A(const A&) = delete; A& operator=(const A&) = delete; A(const B& b, const C& c); } 

Maintenant, j’ai un vecteur de type vector aVector; et je veux y insérer des éléments – j’utilise donc emplace_back :

 aVector.emplace_back(b, c); 

Cependant, cela ne comstack pas avec gcc et j’obtiens l’erreur –

 third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:77:3: required from 'static _ForwardIterator std::__uninitialized_copy::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:119:41: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:260:63: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator&) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/stl_uninitialized.h:283:67: required from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:410:6: required from 'void std::vector::_M_emplace_back_aux(_Args&& ...) third-party/gcc-4.7.1-glibc-2.14.1/libgcc/libgcc-4.7.1/afc21dc/include/c++/4.7.1/bits/vector.tcc:102:4: required from 'void std::vector::emplace_back(_Args&& ...) 

Quelle est la raison de cette erreur et comment peut-on la réparer sans supprimer la suppression des constructeurs de copie? Ai-je besoin d’un constructeur de déménagement? Faut-il le définir explicitement?

Vous devez append le constructeur de déplacement – car std::vector::emplace_back peut effectuer un déplacement qui nécessite un constructeur de copie / déplacement. Ou utilisez simplement std::deque .

DEMO LIVE

 #include  #include  using namespace std; struct NoCopyNoMove { NoCopyNoMove(const NoCopyNoMove&) = delete; NoCopyNoMove& operator=(const NoCopyNoMove&) = delete; NoCopyNoMove(NoCopyNoMove&&) = delete; NoCopyNoMove& operator=(NoCopyNoMove&&) = delete; NoCopyNoMove(int){}; }; struct OnlyMove { OnlyMove(const OnlyMove&) = delete; OnlyMove& operator=(const OnlyMove&) = delete; OnlyMove(OnlyMove&&) noexcept {} OnlyMove& operator=(OnlyMove&&) noexcept {} OnlyMove(int){}; }; int main() { deque x; x.emplace_back(1); vector y; y.emplace_back(1); } 

§ 23.2.3 Tableau 101 – Opérations de conteneur de séquence facultatives

a.emplace_back(args) […]

Nécessite : T doit être EmplaceConstructible en X partir d’arguments. Pour le vector , T doit également être MoveInsertable dans X

L’erreur n’est pas la faute de emplace_back. Pour mettre un object dans un vecteur, il doit être déplaçable ou copié. Si vous exécutez le code avec le constructeur de copie implémenté, vous remarquerez qu’il n’est jamais appelé. Ceci est une entrée sur cppreference.com
entrez la description de l'image ici

Ce que je ferais pour résoudre ce problème est de mettre en œuvre le constructeur de mouvement, ce qui le rend compilé et je ne vois aucun inconvénient réel à avoir un constructeur de mouvement. Et comme avec le cctor, le constructeur de déplacement ne sera pas appelé dans votre code actuel.

J’ai rencontré ce problème avec la classe d’une bibliothèque externe. Je devenais

"Error C2280 ClassName::ClassName(const ClassName &)': attempting to reference a deleted function"

J’imagine que la classe que j’utilisais avait supprimé son constructeur de copie. Je ne pouvais l’append à aucun des conteneurs std je connaissais pour mes objects de classe dérivée personnalisés, qui encapsulaient leur object avec certains de mes assistants pour faciliter les vérifications d’initialisation / d’erreur.

J’ai travaillé autour de ce bloqueur avec des pointeurs ( risqués ).

En gros, je suis passé à ceci:

 std::vector names; ClassName name("arg"); ClassName name_ptr = &name; names.push_back(name_ptr); 

à partir de cela, à l’origine:

 std::vector names; ClassName name("arg"); names.push_back(name); 

Intéressant à dire, c’était la première fois que je codais en C ++ que j’avais besoin d’utiliser des pointeurs pour des besoins d’utilisation non spécifiques à un pointeur, en raison de l’absence d’alternative connue. Cela me fait craindre d’avoir oublié quelque chose de fondamental dans mon propre code.

Peut-être qu’il y a une meilleure façon de faire cela, mais cela ne figure pas encore dans la liste des réponses de cette question …

modifier pour mise en garde:

J’aurais dû en parler plus tôt, merci Aschepler ; Si vous faites cela et que le conteneur que vous utilisez survit à l’object, “Bang, tu es mort”.