C++ vecteur d'objets vs. vecteur de pointeurs sur des objets
Je suis en train d'écrire une application à l'aide openFrameworks, mais ma question n'est pas spécifique à seulement; c'est plutôt une question d'ordre général sur le C++ vecteurs en général.
J'ai voulu créer une classe qui contient plusieurs instances d'une autre classe, mais aussi fournit une interface intuitive pour interagir avec ces objets. En interne, les élèves de ma classe ont utilisé un vecteur de la classe, mais quand j'ai essayé de manipuler un objet à l'aide de vecteur.à(), le programme compile mais ne fonctionne pas correctement (dans mon cas, il ne serait pas afficher une vidéo).
//instantiate object dynamically, do something, then append to vector
vector<ofVideoPlayer> videos;
ofVideoPlayer *video = new ofVideoPlayer;
video->loadMovie(filename);
videos.push_back(*video);
//access object in vector and do something; compiles but does not work properly
//without going into specific openFrameworks details, the problem was that the video would
//not draw to screen
videos.at(0)->draw();
Quelque part, il a été suggéré que je fais un vecteur de pointeurs sur des objets de cette classe au lieu d'un vecteur de ces objets eux-mêmes. Je l'ai fait et en effet, il a travaillé comme un charme.
vector<ofVideoPlayer*> videos;
ofVideoPlayer * video = new ofVideoPlayer;
video->loadMovie(filename);
videos.push_back(video);
//now dereference pointer to object and call draw
videos.at(0)->draw();
Je a allouer de la mémoire pour les objets dynamiquement, c'est à dire ofVideoPlayer = new ofVideoPlayer;
Ma question est simple: pourquoi l'aide d'un vecteur de pointeurs de travail, et quand souhaitez-vous créer un vecteur d'objets par rapport à un vecteur de pointeurs sur ces objets?
- Pouvons-nous un peu de code? Un peu dur de répondre à cette juste une explication.
- Nous ne pouvons pas comprendre pourquoi votre code ne fonctionne pas si vous ne publiez pas tout! S'il vous plaît ajouter un exemple qui met en valeur votre question.
- Le code important n'est probablement pas la
vector
d'utilisation, mais leofVideoPlayer
classe elle-même.
Vous devez vous connecter pour publier un commentaire.
std::vector
est comme une brute tableau alloué avec new et réaffecté lorsque vous essayez de pousser en plus d'éléments que sa taille actuelle.Donc, si elle contient
A
pointeurs, c'est comme si vous étiez la manipulation d'un tableau deA*
.Lorsqu'il a besoin de redimensionner (vous
push_back()
un élément alors qu'il est déjà rempli à sa capacité actuelle), il va créer un autreA*
tableau et la copier dans le tableau deA*
de la précédente vecteur.Si elle contient
A
objets, alors c'est comme si vous étiez à la manipulation d'un tableau deA
, doncA
doit être par défaut constructible si il y a automatique des réaffectations de se produire. Dans ce cas, l'ensemble de laA
des objets copiés aussi dans un autre tableau.Voir la différence? La
A
objets dansstd::vector<A>
pouvez changer d'adresse si vous faites quelques manipulations que nécessite le redimensionnement du tableau interne. C'est là que la plupart des problèmes contenant des objets dansstd::vector
vient de.Un moyen d'utiliser
std::vector
sans avoir de tels problèmes est d'allouer un assez grand tableau à partir du début. Le mot clé ici est "en capacité". Lestd::vector
la capacité est le réel taille de la mémoire tampon dans lequel on va mettre les objets. Donc, pour l'installation de la capacité, vous avez deux choix:1) la taille de votre
std::vector
de la construction pour construire l'objet depuis le début , avec le nombre maximal d'objets - qui appellent des constructeurs de chacun des objets.2) une fois le
std::vector
est construit (mais n'a rien en elle), utiliser sesreserve()
fonction : le vecteur sera alors d'allouer un tampon assez grand (vous offrir le maximum de la taille du vecteur). Le vecteur permettra de définir la capacité. Si vouspush_back()
objets de ce vecteur ouresize()
- dessous de la limite de la taille que vous avez fournies dans lereserve()
appel, il ne sera jamais à réallouer de la mémoire tampon interne, et vos objets pas de changement de l'emplacement dans la mémoire, en faisant des pointeurs vers ces objets toujours valide (certaines affirmations de vérifier que le changement de capacité ne se produit jamais est une excellente pratique).A
ne doit pas être par défaut constructible, btwCe que vous devez savoir à propos de vecteurs en c++, c'est qu'ils ont à utiliser la copie de l'opérateur de la classe de vos objets afin d'être en mesure d'entrer dans le vecteur. Si vous aviez l'allocation de mémoire de ces objets a été automatiquement libéré lorsque le destructeur est appelé, qui pourrait expliquer vos problèmes: votre objet a été copié dans le vecteur ensuite détruits.
Si vous avez, dans votre classe d'objet, un pointeur qui pointe vers une mémoire tampon allouée, une copie de cet objet va pointer vers le même tampon (si vous utilisez la valeur par défaut de la copie de l'opérateur). Si le destructeur désalloue la mémoire tampon, quand la copie destructeur sera appelé, le tampon d'origine sera libéré, donc vos données ne seront plus disponibles.
Ce problème ne se produit pas si vous utilisez des pointeurs, parce que vous avez le contrôle de la durée de vie de vos éléments par le biais des nouvelles/détruire, et le vecteur des fonctions de copie seulement pointeur vers vos éléments.
ofVideoPlayer * video = new ofVideoPlayer;
etpush_back
cette variable locale à un vecteur. Il est garanti pour fonctionner uniquement lorsquevideo
ne laissez pas le contexte jusqu'à l'vector<ofVideoPlayer*> videos
de l'utiliser (par exemple, ils répartis dans le même contexte que dans l'exemple). b) le Passage par valeur (code échec) est plus sécuritaire - ne pas comprendre pourquoi "de votre objet a été copié dans levector
puis détruits." Détruit - pourquoi? On devrait dire, c'est un problème avec des faux/pas de constructeur de copie.Si vous allouez de la mémoire pour les objets à l'aide de
new
, vous êtes de l'allocation sur le tas. Dans ce cas, vous devez utiliser des pointeurs. Toutefois, en C++, la convention est généralement de créer tous les objets sur la pile et de transmettre des copies de ces objets au lieu de passer des pointeurs vers des objets sur le tas.Pourquoi est-ce mieux? C'est parce que le C++ n'a pas de collecte des ordures, afin de la mémoire pour les objets sur le tas ne sera récupéré sauf si vous
delete
l'objet. Toutefois, les objets sur la pile sont toujours détruits lorsqu'ils quittent la portée. Si vous créez des objets sur la pile au lieu de le tas, vous pouvez réduire votre risque de fuites de mémoire.Si vous utilisez la pile au lieu de le tas, vous aurez besoin d'écrire une bonne copie des constructeurs et des destructeurs. Mal écrit copier les constructeurs ou destructeurs peuvent conduire à des fuites de mémoire ou double libère.
Si vos objets sont trop volumineux pour être efficace copié, alors il est acceptable d'utiliser des pointeurs. Cependant, vous devez utiliser de comptage de références pointeurs intelligents (soit le C++0x auto_ptr ou un la bibliothèque Boost pointeurs) pour éviter les fuites de mémoire.
std::auto_ptr
est standard. Il sera obsolète dans C++0x en faveur destd::unique_ptr
.std::shared_ptr
,std::weak_ptr
, etc seront également mis en place. Pile allocations ne sont pas toujours préférable, mais l'utilisation des pointeurs intelligents pour exception sûr tas de gestion de l'est. C'est mieux de passerconst&
les objets autour de vous pour éviter de copier les appels pour la performance.vector
l'addition et de la gestion interne utiliser des copies de l'objet d'origine - si vous prenez une copie est très coûteux, voire impossible, puis à l'aide d'un pointeur est préférable.Si vous faites le
vector
membre d'un pointeur, utilisation d'un pointeur intelligent pour simplifier votre code et de minimiser les risques de fuites.Peut-être que votre classe ne fait pas bon (c'est à dire. de profondeur) copie de la construction/affectation? Si oui, les pointeurs pourrait fonctionner, mais pas des instances de l'objet comme le vecteur membre.
Je n'ai pas de magasin de classes directement dans
std::vector
. La raison en est simple: vous ne savez pas si la classe est dérivée ou pas.E. g.:
Dans les en-têtes:
Dans la source:
Donc je préfère utiliser
shared_ptr
:base
est décidé pour être dérivée. C'est en grande partie différent de la classe générale qui n'est pas destiné à être dérivée (qui n'ont généralement pas de virtuel).L'idée principale de l'utilisation de vecteur est de stocker des objets dans une de poursuivre l'espace, lors de l'utilisation d'un curseur ou pointeur intelligent qui ne se produira pas