2 votes

Pointeur vers un vecteur : la taille est correcte dans la fonction mais 0 dans l'appelant

J'ai une fonction simple que j'ai simplifiée pour qu'elle ne renvoie qu'une liste fictive (pour m'assurer qu'il ne s'agit pas d'une erreur de logique).

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    ...
    values.clear();
    values.push_back(2);
    values.push_back(3);
    cout << "values is of size " << values.size() << endl;
    return &values;
}

puis dans un test cppunit :

vector<AttrValue>* candidateList0 = evaluator->getCandidateList(cl, 0);
cout << candidateList0->size() << endl;

Mais le problème est size() dans le test, est toujours égal à 0, même si la variable cout Le message imprime la taille correcte 2. Qu'est-ce qui peut être faux ?

J'ai essayé un programme simple et tout semble aller bien ...

#include <iostream>
#include <vector>
using namespace std;

vector<int>* test() {
    vector<int> vec { 2, 3, 6, 1, 2, 3 };
    return &vec;
}

int main() {
    cout << test()->size() << endl;
    return 0;
}

4voto

billz Points 28166

Vous retournez une adresse de temporaire de getCandidateList l'objet est libéré lorsque la fonction revient. y accéder est un comportement non défini. Vous pourriez simplement retourner le vecteur, RVO devrait venir s'appliquer et élider la copie :

Essayez :

std::vector<AttrValue> QueryEvaluator::getCandidateList(...) 
{
  //blah
  return values; 
}

J'ai essayé un programme simple et tout semble aller bien ...

le vecteur temporaire est libéré lorsque la fonction getCandidateList revient. Le programme a un comportement indéfini.

2voto

simonc Points 30279

Votre vecteur semble être déclaré sur la pile et sera donc détruit lorsqu'il sortira du champ d'application (lorsque la fonction sortira). Si vous souhaitez renvoyer un pointeur vers un vecteur, allouez-le plutôt sur le tas.

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    vector<AttrValue>* values = new vector<AttrValue>();
    ...
    values->clear();
    values->push_back(2);
    values->push_back(3);
    cout << "values is of size " << values->size() << endl;
    return values;
}

Il pourrait être plus facile de le déclarer dans l'appelant et de passer une référence à getCandidateList

void QueryEvaluator::getCandidateList(vector<AttrValue>& values)

...ou le retourner par valeur

vector<AttrValue> QueryEvaluator::getCandidateList(...) {

1voto

Loki Astari Points 116129

Tant de choses intéressantes à considérer :

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    ...
    values.clear();
    values.push_back(2);
    values.push_back(3);
    cout << "values is of size " << values.size() << endl;
    return &values;
}

On dirait que tu as laissé de côté la partie la plus intéressante du code. ... ci-dessus. La morale de l'histoire est que vous devez fournir un code compilable qui montre l'erreur. Si vous réduisez votre problème à un petit exemple, vous le trouverez vous-même. Au minimum, vous devriez fournir les définitions exactes de tous les objets utilisés (le type est la chose la plus importante en C++).

Déclare-t-il le vecteur comme un objet local ?

 std::vector<int>  values;

Dans ce cas, la durée de vie des vecteurs est liée à la fonction et elle est détruite à la fin de la fonction. Cela signifie que son utilisation après le retour de la fonction est un comportement non défini (tout peut arriver).

Mais il semble également que vous utilisiez des objets dans le cadre de vos tests unitaires. Une solution potentielle est donc de faire en sorte que le vecteur fasse partie de l'objet. Le vecteur vivra alors aussi longtemps que l'objet (et pas seulement l'appel de la fonction) et le fait de renvoyer un pointeur vers lui fonctionnera comme prévu.

 class  QueryEvaluator
 {
     std::vector<int>   values;
     public:
         vector<AttrValue>* QueryEvaluator::getCandidateList(...);
 };

Une alternative serait de retourner le vecteur par valeur plutôt que par un pointeur. Cela signifie que l'objet sera correctement copié hors de la fonction et que le code appelant pourra manipuler et tester le vecteur autant qu'il le souhaite.

vector<AttrValue> QueryEvaluator::getCandidateList(...)
{
    ...
    return &values;
}

Note complémentaire :

Vous devez également essayer de ne pas utiliser de pointeurs dans votre code. Les pointeurs ne transmettent aucune propriété, ce qui signifie que nous ne savons pas qui est responsable de la suppression de l'objet. Dans ce cas, une référence aurait probablement été mieux (vous ne retournez jamais NULL) car cela donne à l'appelant l'accès à l'objet tout en conservant la propriété (en supposant que vous avez décidé de ne pas retourner par valeur).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X