J'ai un std::vector
objet d'une certaine classe A
. La classe n'est pas triviale et a des constructeurs de copie et des constructeurs de déplacement définis.
std::vector<A> myvec;
Si je remplis le vecteur avec des A
objets (en utilisant par exemple myvec.push_back(a)
), le vecteur augmentera en taille, en utilisant le constructeur de copie A( const A&)
pour instancier de nouvelles copies des éléments dans le vecteur.
Puis-je en quelque sorte imposer que le constructeur de mouvement de la classe A
soit utilisé à la place?
Réponses:
Vous devez informer C ++ (spécifiquement
std::vector
) que votre constructeur et destructeur de déplacement ne lance pas, en utilisantnoexcept
. Ensuite, le constructeur de déplacement sera appelé lorsque le vecteur se développera.Voici comment déclarer et implémenter un constuctor de déplacement qui est respecté par
std::vector
:Si le constructeur ne l'est pas
noexcept
, nestd::vector
peut pas l'utiliser, car il ne peut pas garantir les garanties d'exception exigées par le standard.Pour en savoir plus sur ce qui est dit dans la norme, lisez la sémantique et les exceptions C ++ Move
Merci à Bo qui a laissé entendre que cela pourrait avoir à voir avec des exceptions. Tenez également compte des conseils de Kerrek SB et utilisez-les
emplace_back
si possible. Cela peut être plus rapide (mais ce n'est souvent pas le cas), cela peut être plus clair et plus compact, mais il y a aussi quelques pièges (surtout avec les constructeurs non explicites).Modifier , souvent la valeur par défaut est ce que vous voulez: déplacez tout ce qui peut être déplacé, copiez le reste. Pour demander cela explicitement, écrivez
En faisant cela, vous obtiendrez noexcept lorsque cela est possible: le constructeur Move par défaut est-il défini comme noexcept?
Notez que les premières versions de Visual Studio 2015 et les versions antérieures ne le prenaient pas en charge, même s'il prend en charge la sémantique de déplacement.
la source
value_type
l » cteur move estnoexcept
? Peut-être que le langage restreint l'ensemble de candidats à l'appel de fonction lorsque la portée appelante est également unenoexcept
fonction?noexcept
constructeur de déplacement.is_nothrow_move_constructible
sera vrai s'il existe unnothrow
constructeur de copie. Je ne connais aucun cas réel denothrow
constructeurs de copie coûteux , il n'est donc pas clair que cela compte vraiment.noexcept
à la fois dans l'en-tête et dans l'implémentation, et quand je fais un push_back (std:; move), il appelle toujours le constructeur de copie. Je me déchire les cheveux ici.std::move()
sur le mauvaispush_back()
appel. Un de ces moments où vous cherchez si fort un problème que vous ne voyez pas l'erreur évidente juste devant vous. Et puis c'était l'heure du déjeuner et j'ai oublié de supprimer mon commentaire.Fait intéressant, le vecteur de gcc 4.7.2 n'utilise le constructeur de déplacement que si le constructeur de déplacement et le destructeur le sont
noexcept
. Un exemple simple:Cela produit le attendu:
Cependant, lorsque je supprime
noexcept
de~foo()
, le résultat est différent:Je suppose que cela répond également à cette question .
la source
Il semble que le seul moyen (pour C ++ 17 et les versions antérieures) d'imposer la
std::vector
sémantique use move lors de la réallocation est de supprimer le constructeur de copie :). De cette façon, il utilisera vos constructeurs de mouvement ou mourra en essayant, au moment de la compilation :).Il existe de nombreuses règles où il
std::vector
NE DOIT PAS utiliser le constructeur de déplacement lors de la réallocation, mais rien sur l'endroit où il DOIT L'UTILISER .Vivre
ou
Code en direct
Votre
T
classe doit avoirnoexcept
un opérateur de constructeur / d'assignation de déplacement et unnoexcept
destructeur. Sinon, vous obtiendrez une erreur de compilation.la source