Pourquoi std :: queue :: pop ne retourne pas la valeur.

Je suis passé par cette page mais je ne suis pas capable d’obtenir la même raison. Il est mentionné que

“Il est plus judicieux qu’elle ne renvoie aucune valeur et que les clients utilisent front () pour inspecter la valeur au début de la file”

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

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

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

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

sur la cinquième ligne, l’object cout crée d’abord une copie de myqueue.front () puis l’affecte à la suite. Donc, quelle est la différence, la fonction pop aurait pu faire la même chose.

Donc, 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 ce n’est pas le cas, c’est qu’un pop qui a renvoyé l’élément popped est dangereux en présence d’exceptions (devoir renvoyer par valeur et créer ainsi une copie).

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

 template 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 copie de T se retourne, vous avez déjà modifié l’état de la queue ( top_position dans mon implémentation naïve) et l’élément est supprimé de la queue (et n’est pas renvoyé). À toutes fins utiles (peu importe comment vous attrapez l’exception dans le code client), l’élément en haut de la queue est perdu.

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

Cela peut être implémenté en toute sécurité et efficacement, avec deux opérations distinctes ( void pop et const T& front() ).

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. C’est-à-dire, pourquoi doit-on utiliser front () et pop () pour examiner et supprimer l’élément au début de la queue, au lieu de combiner les deux dans une fonction membre unique? En fait, il y a une bonne raison pour cette conception. Si pop () a renvoyé l’élément front, il devrait renvoyer par valeur plutôt que par référence: return by reference créerait un pointeur en suspens. Le retour par valeur est cependant inefficace: il implique au moins un appel de constructeur de copie redondant. Comme il est impossible à pop () de renvoyer une valeur à la fois efficace et correcte, il est plus judicieux qu’elle ne retourne aucune valeur et que les clients utilisent front () pour vérifier la valeur à l’avant de la queue.

C ++ est conçu avec une efficacité en tête, sur le nombre de lignes de code que le programmeur doit écrire.

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

Avec l’implémentation actuelle, ceci est valide:

 int &result = myqueue.front(); std::cout < < result; myqueue.pop(); 

Si pop renvoie une référence, comme ceci:

 value_type& pop(); 

Ensuite, le code suivant pourrait se bloquer, car la référence n'est plus valide:

 int &result = myqueue.pop(); std::cout < < result; 

Par contre, si elle renvoyait directement une valeur:

 value_type pop(); 

Ensuite, vous devez faire une copie pour que ce code fonctionne, ce qui est moins efficace:

 int result = myqueue.pop(); std::cout < < result; 

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

Vous pouvez totalement faire ceci:

 std::cout < < ' ' << myqueue.front(); 

Ou, si vous voulez la valeur dans une variable, utilisez une référence:

 const auto &result = myqueue.front(); if (result > whatever) do_whatever(); std::cout < < ' ' << result; 

À côté de cela: la formulation «plus sensible» est une forme subjective de «nous avons examiné les modèles d'utilisation et avons trouvé plus de besoin d'une scission». (Rassurez-vous: le langage C ++ n’évolue pas à la légère…)

Je pense que la meilleure solution serait d’append quelque chose comme

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

où valeur recevra la valeur éclatée.

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