C++, comment correctement copie std::vector< *> dans le constructeur de copie?
Je suis en utilisant deux classes
//This is generic data structure containing some binary data
class A {
public:
A();
A(const A&);
~A();
}
//Main data container
class B {
public:
B();
B( const B&);
~B();
protected:
std::vector<A *> data;
}
//Copy constructor for class b
B::B( const B& orig):data() {
for( std::vector<A *>::const_iterator it = orig.data.begin();
it < orig.data.end(); ++it){
data.push_back( new A( *(*it)));
}
}
Je suppose que cette classe serait faire le travail, mais je suis la recherche de façon à atteindre le total de la perfection.
Au premier :data()
- est-ce initialisation requis pour initialiser le vecteur vide correctement (et c'est une partie de l'écriture d'un bon et propre code)?
Comment utiliser vector::iterator
dans le constructeur de copie, le seul moyen que j'ai trouvé est celui que j'ai écrit dans le code (const devrait être obligatoire pour le constructeur de copie).
De copier simplement vecteur copier les valeurs de pointeur et non pas l'ensemble des objets?
Et, enfin, de nouvelles données d'initialisation... Est-il de toute façon, comment pourrais-je remplacer la totalité de la boucle avec un plus petit morceau de code et/ou est-il un standard-comment écrire constructeur de std::conteneurs qui contient des pointeurs d'objet?
Sous-question: je suis en supposant à l'aide de vector<A *>
est beaucoup plus approprié et efficace pour diverses raisons que juste vector<A>
(pas la copie de tous les temps, le pouvoir de décider (ou pas) pour copier des objets...)
Préallouer
data
dans la liste des initialiseurs. À l'aide de push_back()
comme ça, c'est très inefficace.Sous réponse: je pense que, si vous ne pas utiliser les pointeurs, vous ne pas de les utiliser.
Je n'ai jamais utilisé de boost, mais je suis sûr qu'il a une solution pour ce problème (il l'a toujours des solutions pour des problèmes qui semblent communs).
Comme la accepté de répondre à des spectacles, l'obtention de ce droit avec l'ensemble de la gestion des exceptions est une douleur. Un vecteur de pointeurs intelligents ou un
std::deque
d'objets est généralement mieux. (Aussi, pour les petits objets, un vecteur de pointeurs est généralement plus lent que un vecteur d'objets, trop d'indirections et les appels à new/delete)
OriginalL'auteur Vyktor | 2012-01-14
Vous devez vous connecter pour publier un commentaire.
La
data()
n'est pas nécessaire parce que ce sera fait automatiquement à l'vecteur avant que le constructeur est entré. Vous avez seulement besoin de l'initialiser les membres qui sont POD ou de types de types qui n'ont pas de constructeur par défaut (ou des références, des constantes, etc).Vous pouvez initialiser le vecteur avec le nombre d'éléments que l'autre a, de sorte que le vecteur ne pas avoir à redimensionner lui-même à mesure qu'il grandit. Si vous ne le faites pas, vous commencez avec un petit vecteur et de le rendre progressivement atteindre la destination de la taille via des allocations et des réaffectations. Cela permettra de faire le vecteur de la bonne taille dès le début:
Avis que vous n'êtes pas à l'aide de
push_back
plus, parce que le vecteur est déjà plein deorig.data.size()
certain nombre d'éléments qui sont par défaut construit (ce qui estNULL
dans le cas des pointeurs).Ce aussi les garnitures de bas le code, car vous pouvez utiliser un nombre entier de le parcourir au lieu d'un itérateur.
Si vous voulez vraiment utiliser des itérateurs, vous pouvez le faire
L'avantage, c'est qu'il va travailler avec d'autres types de conteneurs (comme
list
) en changeant juste les types d'itérateurs (mais ce serait aller loin si vous avezauto
).Si vous souhaitez ajouter une exception de sécurité, vous avez besoin d'un
try/catch
bloc:De cette façon, vous n'aurez pas une fuite de mémoire si l'un des
new
appels déclenche une exception. Bien sûr, vous pouvez utiliser letry/catch
avec la façon que sans les itérateurs si vous préférez le faire de cette façon.orig.data[i]
.oups, vous avez raison, fixe.
Une chose de plus à prendre en considération est la gestion des erreurs: qu'advient-il si l'un des
new
s échouer dans le milieu de la boucle? Probablement le programme sera juste de terminer, mais si l'erreur de mémoire insuffisante est traitée plus haut dans la pile d'appel, vous aurez une fuite de mémoire.veuillez passer en revue de ma dernière modifier pour voir si qui gère la situation que vous êtes en train de parler.
fait appel
delete
sur un pointeur null est défini à ne rien faire. Je ne sais pas pourquoi j'ai mis*i
à null, ce qui semblait une bonne idée à l'époque 🙂 Au moins, maintenant je peux me débarrasser de ces accolades.OriginalL'auteur Seth Carnegie