J'apprends les vecteurs et j'ai rencontré un problème qui pose le défi de créer un vecteur d'éléments en utilisant des pointeurs vers des chaînes
void display(vector<string*> items) { for (int i = 0; i <= items.size(); i++) { cout << "> " << *items[i] << "\n"; } return; }
J'essaie d'ajouter des éléments en passant la liste via référence à la fonction ci-dessous:
void add_item(vector<string*> &items) { string thing; cout << "Add this item: "; cin >> thing; string* ptr = &thing; items.push_back(ptr); return; }
puis en affichant tous les éléments en utilisant:
vector<string*> items;
Mais cela ne semble pas fonctionne, il n'y a pas de sortie sur l'écran, puis le programme se termine au hasard. Qu'est-ce que je fais de mal ici?
3 Réponses :
Vous ajoutez un pointeur sur la chaîne chose
au vecteur de pointeurs sur les chaînes. Mais dès que add_item
revient, thing
sort de la portée. Ainsi, le pointeur que vous avez ajouté est maintenant un pointeur vers rien.
Pourquoi avez-vous besoin d'un vecteur de pointeurs? Ce n'est presque jamais vrai.
Je n'irais pas jusqu'à dire que le vecteur du pointeur n'est presque jamais correct. C'est rare, bien sûr. Un pointeur vers un std :: string
cependant. Je ne me souviens pas avoir jamais eu besoin de ça.
Comment accéder aux éléments d'un vecteur contenant des pointeurs vers des chaînes?
Comme ceci:
{ std::string thing = "example"; items.push_back(&thing); display(items); items.pop_back(); // erase the pointer that is about to be invalidated } // the string no longer exists here
Cependant, le pointeur dans le vecteur doit pointer vers un objet valide ou bien le comportement d'accès à l'objet via le pointeur n'est pas défini .
Dans votre exemple, la chaîne est une variable automatique dans
add_item
. Au retour de la fonction, toutes les variables automatiques, y compris la chaîne, sont automatiquement détruites. À ce stade, le pointeur dans le vecteur est devenu invalide. Le comportement de l’indexation via le pointeur et de l’accès à l’objet n’est pas défini.Qu'est-ce que je fais de mal ici?
Vous essayez d'accéder via un pointeur invalide et le comportement du programme n'est pas défini.
Voici un exemple correct utilisant un vecteur de pointeurs:
*items[i]Remarquez comment la chaîne existe toujours lorsqu'elle est affichée.
Mais, vous devriez probablement utiliser
std :: vector
code> à la place afin d'éviter des problèmes comme celui-ci.
Dans votre fonction add_item ()
, thing
est une variable locale . Vous insérez son adresse dans le vecteur, mais lorsque la fonction retourne alors chose
n'existe plus, donc le pointeur stocké dans votre vecteur est invalide, et tenter de le déréférencer plus tard entraînera un comportement indéfini.
Comme mentionné dans les commentaires, ce que vous voulez probablement est un vecteur d'objets string
objets , plutôt que de string
pointeurs em >.
Cependant, si vous avez vraiment besoin d'utiliser un vector
(bien que je ne vois pas le besoin, et c'est pas quelque chose que je recommanderais), alors vous devriez créer une nouvelle chaîne dans votre fonction add_item ()
(et, bien sûr, puis la supprimer
lorsque vous la supprimerez plus tard du vector):
vector<string*> items; add_item(items); ... for (size_t i = 0; i < items.size(); ++i) { delete items[i]; }
void add_item(vector<string*> &items) { string *thing = new string; cout << "Add this item: "; cin >> *thing; items.push_back(thing); return; }
Dans ce cas, le chose
est créé sur le tas em > et restera valide après le retour de la fonction.
Lorsque vous montrez des exemples avec la possession de pointeurs nus, je mettrais en garde contre les fuites de mémoire, les plantages sans double, la sécurité des exceptions, etc.
@eerorika Fair point! ai-je mentionné la nécessité de supprimer
mais peut-être un peu plus? Je vais y réfléchir.
Si vous allez stocker des pointeurs comme celui-ci, utilisez plutôt std::vector
, alors vous n'avez pas à vous soucier d'appeler delete
manuellement.
@RemyLebeau Nice edit - merci pour ça! J'ai considéré un exemple utilisant unique_ptr
mais OP semblait vouloir utiliser des pointeurs bruts (du moins, c'est ainsi que j'ai compris la question).
Il y a de fortes chances que vous ne vouliez pas d'un vecteur de pointeurs vers des chaînes. Vous voulez probablement un vecteur de chaînes. À moins que vous n'utilisiez des objets polymorphes, vous ne voulez pas de vecteur de pointeurs d'aucune sorte.
@AdrianMole C'est ma faute, je l'ai fait accidentellement en tapant ma question. Je viens de faire le montage.
@Ron C'est ce que je pensais aussi, mais c'est ce que suggère la question
@dankpenny Par ailleurs, votre boucle
display ()
sort des limites duvecteur
. Il doit utiliser<
au lieu de<=
, et il doit utiliservector :: size_type
(qui est généralementsize_t
) au lieu deint
.