Les fonctions de retour des objects sont-elles des objects automatiques et garantissent-elles ainsi leur destruction?

Dans [except.ctor], le standard ( N4140 ) garantit que:

… les destructeurs sont appelés pour tous les objects automatiques construits depuis la saisie du bloc try …

Cependant, dans l’exemple suivant, la sortie vide prouve que la valeur de retour de la fonction foo n’est pas détruite, bien qu’elle ait été construite. Compilé avec g ++ (5.2.1) et clang ++ (3.6.2-1) et avec les options -O0 -fno-elide-constructors -std=c++14 .

 struct A { ~A() { cout << "~A\n"; } }; struct B { ~B() noexcept(false) { throw 0; } }; A foo() { B b; return {}; } int main() { try { foo(); } catch (...) { } } 

Est-ce un bug à la fois dans g ++ et clang ++, ou les valeurs de retour de fonction ne sont-elles pas considérées comme des objects automatiques, ou s’agit-il d’un trou de boucle dans le langage C ++?

Dans aucun de [stmt.return], [expr.call] ou [dcl.fct], j’ai pu trouver une déclaration claire indiquant si une valeur de retour de fonction est considérée comme un object automatique. Les indices les plus proches que j’ai trouvés sont 6.3.3 p2:

… Une déclaration de retour peut impliquer la construction et la copie ou le déplacement d’un object temporaire …

et 5.2.2 p10:

Un appel de fonction est une valeur lvalue si le type de résultat est un type de référence lvalue ou une référence de valeur à un type de fonction, une valeur x si le type de résultat est une référence à un type d’object et une valeur sinon.

    Les valeurs de retour de fonction sont considérées comme temporaires et la construction de la valeur de retour est séquencée avant la destruction des locaux.

    Malheureusement, ceci est sous-spécifié dans la norme. Il y a un défaut ouvert qui décrit ceci et offre un libellé pour résoudre le problème

    […] Une instruction de retour avec un opérande de type void ne doit être utilisée que dans une fonction dont le type de retour est cv void. Une déclaration de retour avec tout autre opérande ne doit être utilisée que dans une fonction dont le type de retour n’est pas vide cv; l’instruction return initialise l’object ou la référence à renvoyer par initialisation de copie (8.5 [dcl.init]) à partir de l’opérande. […]

    L’initialisation de la copie de l’entité retournée est séquencée avant la destruction des temporelles à la fin de la pleine expression établie par l’opérande de l’instruction return, qui est elle-même séquencée avant la destruction des variables locales (6.6 [stmt. jump]) du bloc contenant la déclaration de retour.

    Les valeurs de retour de fonction étant temporaires, elles ne sont pas couvertes par les destructors are invoked for all automatic objects . Elles sont destructors are invoked for all automatic objects devis destructors are invoked for all automatic objects au début de votre publication. Cependant, [class.temporary]/3 dit:

    […] Les objects temporaires sont détruits comme dernière étape dans l’évaluation de la pleine expression qui contient (lexicalement) le point où ils ont été créés. Cela est vrai même si cette évaluation finit par lancer une exception . […]

    Donc, je pense que vous pourriez considérer cela comme un bug dans GCC et Clang.

    Ne jetez pas de destructeurs;)

    Ceci est un bogue, et pour une fois, MSVC a tout à fait raison: il imprime “~ A”.

    J’ai modifié votre code et je pense que maintenant, à partir de la sortie, nous pouvons voir que A n’est pas détruit.

     #include using namespace std; struct A { ~A() { cout << "~A\n"; } A() { cout << "A()"; } }; struct B { ~B() noexcept( false ) { cout << "~B\n"; throw(0); } B() { cout << "B()"; } }; A foo() { B b; return; } int main() { try { foo(); } catch (...) {} } 

    Et la sortie est la suivante:

    B () A () ~ B

    Alors oui, ça pourrait être un bug.