1
votes

Comment accéder aux éléments d'un vecteur contenant des pointeurs vers des chaînes?

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?


4 commentaires

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 du vecteur . Il doit utiliser < au lieu de <= , et il doit utiliser vector :: size_type (qui est généralement size_t ) au lieu de int .


3 Réponses :


1
votes

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.


1 commentaires

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.



1
votes

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.


0 commentaires

2
votes

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.


4 commentaires

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).