42 votes

C++ meilleure pratique: le Retour de référence vs. objet

Je suis en train d'apprendre le C++, et d'essayer de comprendre le retour des objets. Il me semble voir 2 façons de le faire, et la nécessité de comprendre quelle est la meilleure pratique.

Option 1:

QList<Weight *> ret;
Weight *weight = new Weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return &ret;

Option 2:

QList<Weight *> *ret = new QList();
Weight *weight = new Weight(cname, "Weight");
ret->append(weight);
ret->append(c);
return ret;

(bien sûr, je ne peut pas comprendre ce encore).

Ce qui est considéré comme la meilleure pratique, et devrait être suivie?

48voto

Potatoswatter Points 70305

L'Option 1 est défectueux. Lorsque vous déclarez un objet

QList<Weight *> ret;

il ne vit que dans la portée locale. Il est détruit lorsque la fonction se termine. Cependant, vous pouvez faire ce travail avec

return ret; // no "&"

Aujourd'hui, bien qu' ret est détruit, une copie de la première et transmis à l'appelant.

Ceci est généralement préférée à la méthodologie. En fait, la copie et la détruire de l'opération (qui ne sert à rien, vraiment) est généralement élidés, ou optimisé à et vous obtenez un rapide, élégant programme.

Option 2 fonctionne, mais alors vous avez un pointeur sur le tas. Une façon de regarder le C++, c'est que l'usage de la langue est pour éviter le manuel de gestion de la mémoire comme ça. Parfois, vous ne voulez gérer des objets sur le tas, mais l'option 1 permet encore que:

QList<Weight *> *myList = new QList<Weight *>( getWeights() );

getWeights est votre exemple de fonction. (Dans ce cas, vous pouvez avoir à définir un constructeur de copie QList::QList( QList const & ), mais à l'instar de l'exemple précédent, il ne sera probablement pas appelé.)

De même, vous devriez probablement éviter d'avoir une liste de pointeurs. La liste doit stocker directement les objets. Essayez d'utiliser std::list... pratique avec les possibilités de la langue est plus important que la pratique de la mise en œuvre de structures de données.

7voto

missingfaktor Points 44003

Utilisez l'option #1 avec une légère modification; au lieu de retourner une référence à l'créés localement objet, de retour de sa copie.

c'est à dire return ret;

La plupart des compilateurs C++ effectuer la valeur de Retour d'optimisation (RVO) pour optimiser loin l'objet temporaire créée pour détenir une fonction de la valeur de retour.

5voto

Michael Aaron Safyan Points 45071

En général, vous ne devriez jamais vous retourner une référence ou un pointeur. Au lieu de cela, retourner une copie de l'objet ou de retourner un pointeur intelligent de la classe qui possède l'objet. En général, l'utilisation statique d'allocation de stockage, à moins que la taille varie en fonction au moment de l'exécution ou de la durée de vie de l'objet doit être alloués à l'aide de dynamic allocation de stockage.

Comme cela a été souligné, de votre exemple de retour par référence renvoie une référence à un objet qui n'existe plus (depuis qu'il a disparu hors de portée) et sont donc en invoquant un comportement indéfini. C'est la raison pour laquelle vous ne devriez jamais retourner une référence. Vous ne devriez jamais vous retourner un pointeur brut, parce que la propriété est incertaine.

Il convient également de noter que le retour par valeur est incroyablement bon marché en raison de retourner la valeur de l'optimisation (RVO), et va bientôt être encore moins cher en raison de l'introduction de références rvalue.

1voto

Jive Dadson Points 3563

C'est généralement une mauvaise pratique d'allouer de la mémoire qui doit être libéré ailleurs. C'est une des raisons qui nous ont C++ plutôt que de simplement C. (Mais savvy programmeurs ont écrit le code orienté objet en C long avant l'Âge de Stroustrup.) Bien construit les objets ont de copie rapide et opérateurs d'affectation (parfois à l'aide de comptage de références), et elles sont automatiquement libérer de la mémoire qu'ils "propre" quand ils sont libérés et leur DTOR est automatiquement appelé. De sorte que vous pouvez les jeter autour gaiement, plutôt que d'utiliser des pointeurs vers eux.

Par conséquent, selon ce que vous voulez faire, la meilleure pratique est très probable que "rien de ce qui précède." Chaque fois que vous êtes tenté d'utiliser "nouveaux" autre part que dans un CTOR, pensez à ce sujet. Probablement vous ne voulez pas utiliser de "nouveau" à tous. Si vous le faites, le pointeur résultant devrait probablement être enveloppé dans une sorte de pointeur intelligent. Vous pouvez passer des semaines et des mois sans jamais l'appel de la "nouvelle", car le "nouveau" et "supprimer" sont pris en charge dans les classes standard ou modèles de classe comme std::list et std::vector.

Une exception est lorsque vous utilisez une ancienne la mode de la bibliothèque comme OpenCV qui parfois nécessite que vous créez un nouvel objet, et de la main d'un pointeur vers elle pour le système, qui en prend possession.

Si QList et le Poids sont correctement écrit à nettoyer après eux-mêmes dans leur DTORS, ce que vous voulez, c'est,

QList<Weight> ret();
Weight weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return ret;

1voto

Agnel Kurian Points 14231

Comme déjà mentionné, il est préférable d'éviter d'allouer de la mémoire qui doit être libéré ailleurs. C'est ce que je préfère faire (...ces jours-ci):

void someFunc(QList<Weight *>& list){
    // ... other code
    Weight *weight = new Weight(cname, "Weight");
    list.append(weight);
    list.append(c);
}

// ... later ...

QList<Weight *> list;
someFunc(list)

Encore mieux, éviter new complètement et à l'aide de std::vector:

void someFunc(std::vector<Weight>& list){
    // ... other code
    Weight weight(cname, "Weight");
    list.push_back(weight);
    list.push_back(c);
}

// ... later ...

std::vector<Weight> list;
someFunc(list);

Vous pouvez toujours utiliser un bool ou enum si vous souhaitez retourner un indicateur d'état.

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