9
votes

Pourquoi POP () devrait prendre un argument?

arrière-plan rapide fort>
Je suis un développeur Java qui joue avec C ++ dans mon temps libre / ennuyé.

Préface forte>

En C ++, vous voyez souvent Pop prenant un argument par référence: P>

Item pop() throws StackException;


0 commentaires

5 Réponses :


26
votes

Pour répondre à la question: Vous ne devez pas implémenter la fonction POP en C ++, car elle est déjà mise en œuvre par la STL. std :: pile adaptateur de conteneur fournit le Méthode TOP Pour obtenir une référence à l'élément supérieur de la pile et la méthode pop pour supprimer l'élément supérieur. Notez que la méthode POP seule ne peut être utilisée seul pour effectuer les deux actions, comme vous l'avez posé de questions.

Pourquoi devrait-il être fait de cette façon?

  1. Sécurité des exceptions: Herb Sutter donne une bonne explication du problème dans Gotw # 82 .
  2. Principe de responsabilité unique: a également mentionné dans Gotw # 82. haut prend en charge une responsabilité et pop prend soin de l'autre.
  3. Ne payez pas ce que vous n'avez pas besoin: Pour certains code, il peut suffire d'examiner l'élément supérieur, puis de le faire sauter sans jamais faire une copie (potentiellement coûteuse) de la élément. (Ceci est mentionné dans le SGI STL Documentation.)

    n'importe quel code qui souhaite obtenir une copie de l'élément peut le faire sans frais supplémentaires: xxx

    aussi, Cette discussion peut être intéressante.

    Si vous alliez Pour mettre en œuvre la pop pour renvoyer la valeur, cela n'a pas beaucoup d'importance si vous revenez de valeur ou écrivez-le dans un paramètre OUT. La plupart des compilateurs implémentent RVO , qui optimisera la méthode de retour-valeur pour être tout aussi efficace. comme méthode de copie-sortie-paramètre. Gardez simplement à l'esprit que l'un de ceux-ci sera probablement moins efficace que d'examiner l'objet à l'aide du sommet () ou de l'avant (), car dans ce cas, il n'y a absolument aucune copie terminée.


5 commentaires

Des liens géniaux, merci beaucoup. Donc, si on me demande dans une interview de mettre en œuvre POP () en C ++ ... Devrais-je leur donner votre réponse? : p


+ 1 ... Mais peut-être "Si vous implémentez la fonction POP en C ++, vous devez suivre l'interface de conteneur standard."


@Stephano: Cela dépend de ce que l'intervieweur veut. Certains peuvent être convaincus que vous connaissez sur std :: pile et savoir qu'il a appuyez sur , haut et pop méthodes. Certains peuvent vouloir que vous appliquiez votre propre pile à l'aide d'un tableau de longueur fixe, juste pour voir si vous pouvez le faire.


BTW une bonne question de suivi, si une personne interviewée mentionnée std :: pile , serait de demander quel type de conteneur sous-jacent est utilisé dans cet adaptateur et pourquoi c'est un bon choix.


@Dan: Vous devriez préciser la réponse que le std :: pile :: pop () a une interface différente de celle de la question (c.-à-d., Que pop () ON; Y Ajuste le conteneur, il ne renvoie pas l'élément supérieur en tant que valeur RTURN ou via une référence transmise).



4
votes

Le problème avec l'approche Java est que sa méthode pop () a au moins deux effets: supprimer un élément et renvoyer un élément. Cela viole le principe de la conception logicielle unique, qui ouvre à son tour la porte des complexités de conception et d'autres problèmes. Cela implique également une pénalité de performance.

à la manière de la manière stl des choses que l'idée est que parfois lorsque vous POP () Vous n'êtes pas intéressé par l'élément sauté. Vous voulez juste que l'effet de suppression de l'élément supérieur. Si la fonction renvoie l'élément et que vous l'ignorez, c'est une copie gaspillée.

Si vous fournissez deux surcharges, un qui prend une référence et une autre qui ne permet pas à l'utilisateur de choisir s'il est intéressé par l'élément renvoyé ou non. La performance de l'appel sera optimale.

La STL ne surcharge pas les fonctions POP (POP () , mais les divise plutôt en deux fonctions: retour () (ou haut () Dans le cas de l'adaptateur std :: pile adaptateur) et pop () . La fonction back () renvoie simplement l'élément, tandis que la fonction pop () la supprime simplement.


4 commentaires

Une fonction qui a deux effets en tant qu'opération atomique unique ne viole pas le principe de la conception logicielle unique.


@Dave Combien de raisons sont là pour changer pour une fonction pop () qui supprime et renvoie un élément? Si vous pouvez compter plus d'un, il viole le principe de la responsabilité unique.


@Wilhelm - une exigence de pop () pour certaines implémentations de la file d'attente en Java est qu'il fait les deux actions atomique .


Le principe de la responsabilité unique concerne la responsabilité des classes ou des composants de votre système, et non des effets des méthodes. Vous pouvez prendre des principes de conception trop loin, vous savez.



0
votes

La seule raison pour laquelle je peux voir pour utiliser cette syntaxe en C ++: xxx

est si vous craignez des copies inutiles.

Si vous retournez la élément , il peut nécessite une copie supplémentaire de l'objet, qui peut être coûteux.

en réalité, Compilateurs C ++ sont très bons à la copie élision et implémentent presque toujours l'optimisation des valeurs de retour (souvent même lorsque vous compilez avec des optimisations désactivées), ce qui rend le point moot et peut même signifier que la version simple "retour par valeur" devient plus vite dans certains cas.

mais si vous êtes en optimisation prématurée (si vous êtes inquiet que le compilateur pourrait ne pas optimiser la copie, même si dans la pratique? EM> le faire), vous pourriez discuter de "retourner" paramètres en attribuant un paramètre de référence.

Plus d'informations ICI


0 commentaires

0
votes

imo, une bonne signature pour l'équivalent de la fonction pop de Java en C ++ serait quelque chose comme: xxx

Utiliser les types d'options est le meilleur moyen de renvoyer quelque chose qui peut être disponible ou non.


0 commentaires

1
votes

Utiliser c ++ 0x rend le tout fort dur.

comme xxx

permet de déplacer efficacement l'élément supérieur de la pile. Tandis que xxx

ne permet pas ces optimisations.


1 commentaires

item = std :: mouvement (pile.top ()); stack.pop (); fonctionne efficacement. La chose intéressante à noter est que la principale raison de cette conception en C ++ 03 (sécurité d'exception) n'est plus le cas en C ++ 11 (car les constructeurs de déplacement doivent être sans lancer).