openclassroom - vector c++




Pourquoi std:: queue:: pop ne renvoie pas la valeur.? (5)

Alors, quelle est la différence, la fonction pop aurait pu faire la même chose.

Il aurait en effet pu faire la même chose. La raison pour laquelle cela n'a pas été le cas, c'est qu'un pop qui a retourné l'élément sauté est dangereux en présence d'exceptions (devoir retourner en valeur et donc créer une copie).

Considérons ce scénario (avec une implémentation pop naïve / inventée, pour illustrer mon propos):

template<class T>
class queue {
    T* elements;
    std::size_t top_position;
    // stuff here
    T pop()
    {
        auto x = elements[top_position];
        // TODO: call destructor for elements[top_position] here
        --top_position;  // alter queue state here
        return x;        // calls T(const T&) which may throw
    }

Si le constructeur de la copie de T renvoie en retour, vous avez déjà modifié l'état de la file d'attente ( top_position dans mon implémentation naïve) et l'élément est retiré de la file d'attente (et non retourné). Pour toutes fins utiles (peu importe comment vous attrapez l'exception dans le code client) l'élément en haut de la file d'attente est perdu.

Cette implémentation est également inefficace dans le cas où vous n'avez pas besoin de la valeur éclatée (c'est-à-dire qu'elle crée une copie de l'élément que personne n'utilisera).

Cela peut être mis en œuvre de manière sûre et efficace, avec deux opérations distinctes ( void pop et const T& front() ).

Je suis passé par cette page mais je ne suis pas en mesure d'obtenir la raison de la même chose. Là, il est mentionné que

"il est plus judicieux de ne retourner aucune valeur et d'obliger les clients à utiliser front () pour inspecter la valeur au début de la file"

Mais inspecter un élément de front () nécessitait également que cet élément soit copié dans lvalue. Par exemple dans ce segment de code

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);

/ * ici temporaire sera créé sur RHS qui sera affecté au résultat, et dans le cas où les retours par référence alors le résultat sera rendu invalide après l'opération pop * /

result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();

sur la cinquième ligne, l'objet cout crée d'abord une copie de myqueue.front () puis l'affecte au résultat. Alors, quelle est la différence, la fonction pop aurait pu faire la même chose.


A partir de Cx11, il serait possible d'archiver le comportement souhaité en utilisant la sémantique de déplacement. Comme pop_and_move. Le constructeur de copie ne sera donc pas appelé, et les performances dépendront uniquement du constructeur de déplacement.


Je pense que la meilleure solution serait d'ajouter quelque chose comme

std::queue::pop_and_store(value_type& value);

où la valeur recevra la valeur sautée.

L'avantage est qu'il pourrait être implémenté en utilisant un opérateur d'assignation de mouvement, tandis que l'utilisation de front + pop fera une copie.


La page que vous avez liée répond à votre question.

Pour citer toute la section pertinente:

On peut se demander pourquoi pop () renvoie void, au lieu de value_type. Autrement dit, pourquoi doit-on utiliser front () et pop () pour examiner et supprimer l'élément en tête de file, au lieu de combiner les deux dans une seule fonction membre? En fait, il y a une bonne raison pour cette conception. Si pop () renvoyait l'élément front, il devrait retourner par valeur plutôt que par référence: return by reference créerait un pointeur dangling. Le retour par valeur est cependant inefficace: il implique au moins un appel de constructeur de copie redondant. Comme il est impossible pour pop () de retourner une valeur de manière à la fois efficace et correcte, il est plus judicieux de ne renvoyer aucune valeur et d'obliger les clients à utiliser front () pour inspecter la valeur à le devant de la file d'attente.

C ++ est conçu pour être efficace, sur le nombre de lignes de code que le programmeur doit écrire.


pop ne peut pas renvoyer une référence à la valeur supprimée, car elle est supprimée de la structure de données, alors à quoi la référence doit-elle faire référence? Il pourrait revenir en valeur, mais que se passe-t-il si le résultat de pop n'est stocké nulle part? Ensuite, le temps est gaspillé à copier la valeur inutilement.





stl