4 votes

std::move() ou son équivalent explicite sur une variable locale peut-il permettre l'élision ?

Par exemple :

Big create()
{
    Big x;
    return std::move(x);
//  return static_cast<typename std::remove_reference<T>::type&&>(t) // why not elide here?
}

En supposant que l'application std::move() pour retourner une variable locale inhibe la sémantique du mouvement parce que les compilateurs ne peuvent pas faire d'hypothèses sur le fonctionnement interne des fonctions en général, mais qu'en est-il des cas où ces hypothèses ne sont pas nécessaires, par exemple lorsque :

  1. std::move(x) est inlined (probablement toujours)
  2. std::move(x) s'écrit comme suit : static_cast<typename std::remove_reference<T>::type&&>(t)

Selon la norme actuelle, une implémentation est autorisée à appliquer le NRVO...

- dans une déclaration de retour dans une fonction avec un type de retour de classe, lorsque l'expression l'expression est le nom d'un objet automatique non volatile (autre que un paramètre de fonction ou une variable introduite par l déclaration d'exception d'un gestionnaire (18.3)) de même type (sans tenir compte de la qualification cv) que l'objet. (en ignorant la qualification cv) que le type de retour de la fonction, l'opération de copie/déplacement l'opération de copie/déplacement peut être omise en construisant l'objet automatique directement dans l'objet de retour de l'appel de fonction

De toute évidence, ni 1) ni 2) ne sont admissibles. Outre le fait que l'utilisation de std::move() pour retourner une variable locale est redondant, pourquoi Cette restriction est-elle nécessaire ? ?

2voto

SergeyA Points 2159

Après avoir relu la question, je la comprends différemment. Je lis la question comme suit Pourquoi ? std::move() inhibe le (N)RVO'

La citation de la norme fournie dans la question est mal mise en évidence. Elle devrait être

dans une déclaration de retour d'une fonction avec un type de retour de classe, lorsque l'expression expression est le nom d'un objet automatique non volatile (autre qu'un un paramètre de fonction ou une variable introduite par la fonction déclaration d'exception d'un gestionnaire (18.3)) avec le même type (en ignorant la qualification cv) comme type de retour de la fonction

Ce qui inhibe le NRVO ici n'est pas que std::move() est appelé, mais le fait que la valeur de retour de std::move n'est pas X mais X&& . Il s'agit de ne correspond pas à la signature de la fonction !

2voto

Nir Friedman Points 3165

Vous devez être clair sur ce que signifie exactement "autoriser l'élision". Tout d'abord, le compilateur peut faire tout ce qu'il veut, en vertu de la règle "as-if". C'est-à-dire que le compilateur peut produire n'importe quel assemblage qu'il veut, tant que cet assemblage se comporte correctement. Cela signifie que le compilateur peut élider n'importe quel constructeur qu'il veut, mais il doit prouver que le programme se comportera de la même manière, que le constructeur soit appelé ou non.

Alors pourquoi des règles spéciales pour l'élision ? Eh bien, il s'agit de cas où le compilateur peut élider les appels de constructeurs (et donc aussi les appels de destructeurs). sans prouvant que le comportement est le même. Ceci est très utile, car il y a beaucoup de types où le constructeur est très peu trivial (comme disons, string ), et les compilateurs en pratique ne sont généralement pas capables de prouver qu'ils sont sûrs d'élider (dans un délai raisonnable) (dans le passé, il y avait même un manque de clarté sur le fait de savoir si l'optimisation d'une allocation de tas était légale pour commencer, puisqu'il s'agit fondamentalement de la mutation d'une variable globale).

Nous voulons donc avoir l'élision pour des raisons de performance. Cependant, il s'agit essentiellement de désigner un cas spécial dans la norme, en termes de comportement. Plus le cas spécial est important, plus nous introduisons de la complexité dans la norme. L'objectif devrait donc être de faire en sorte que la situation autorisée pour l'élision soit suffisamment large pour couvrir les cas utiles qui nous intéressent, mais pas plus.

Vous abordez la question sous l'angle suivant : pourquoi ne pas rendre le cas particulier aussi important que possible ? En réalité, c'est le contraire. Pour étendre les situations autorisées pour l'élision, il faut montrer que cela en vaut vraiment la peine.

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