web-dev-qa-db-fra.com

Puis-je créer une référence à une variable membre ne figurant pas dans la liste dans la liste d'initialisation des membres?

Considérer:

#include <string>
#include <iostream>

class Foo
{
     public:
         Foo( char const * msg ) : x( y ) 
         {
             y = msg;
         }

         std::string const & x;

     private:
         std::string y;
};

int main( int argc, char * argv[] )
{
    if ( argc >= 2 )
    {
        Foo f( argv[1] );
        std::cout << f.x << std::endl;
    }
}

Cela compile et affiche le premier paramètre ... mais je doute que ce soit réellement "légal"/bien formé. Je sais que la liste d'initialisation doit initialiser les variables dans l'ordre de leur déclaration dans la classe, de manière à ne pas référencer les variables qui n'ont pas encore été initialisées. Mais qu'en est-il des variables membres pas dans la liste d'initialisation ? Puis-je créer en toute sécurité des références à ceux-ci?

(L’exemple n’a naturellement aucun sens. C’est juste pour clarifier ce dont je parle.)

17
DevSolar

Tu peux le faire1 parce que:

  1. x et y sont déjà dans la portée ( [basic.scope.class]/1 ).
  2. Puisque vous obtenez une référence après que le constructeur a commencé à exécuter ( [class.cdtor]/1 ) et que le stockage de y est déjà obtenu ( [basic.life]/7 ), cette référence peut être liée à y.

L'utilisation de cette référence dans l'instruction composée du constructeur (une fois l'initialisation du membre terminée) convient également. En effet, y est considéré comme étant initialisé et x fait maintenant référence à un objet dont la durée de vie a commencé.


1 - Il y a une mise en garde pour les avocats de la langue. Techniquement, une référence doit être liée à un objet valide ( [dcl.ref]/5 ), c'est-à-dire dont le cycle de vie a commencé. Cependant, comme Core Language numero 363 details, il devrait fonctionner! La formulation problématique et une résolution possible sont discutées dans Core Language issue 453 (avec la permission de @ T.C. Dans un commentaire supprimé). Il y a un bogue dans la norme, mais votre code est censé être bien formé, et les implémentations en sont généralement conscientes .

21
StoryTeller

Mais qu'en est-il des variables membres qui ne figurent pas dans la liste d'initialisation?

Que les variables soient ou non dans la liste d'initialisation, est sans importance à cet égard. Si une variable ne figure pas dans la liste d'initialisation (ni d'initialiseur de membre par défaut), elle est initialisée par défaut.

y est initialisé après x. Ce n'est pas à cause de la liste d'initialisation des membres, car la liste d'initialisation des membres n'affecte pas l'ordre d'initialisation des membres. Les membres sont initialisés dans l'ordre de leur déclaration.

Cependant, si y est initialisé ou non est également sans importance. Il est bien formé pour lier une référence à un membre avant que le membre ne soit initialisé (à l'exception de la liaison à une base virtuelle de membre non initialisé, qui aurait UB).


En ce qui concerne sécurité (ou peut-être exactitude plus précisément), je vous recommande de prendre le temps de réfléchir à ce qui se passe lorsque Foo est copié. À quoi x fera-t-il référence? Est-ce ce que l'utilisateur de la classe s'attendrait?

3
eerorika

Puis-je créer en toute sécurité des références à ceux-ci?

Oui, vous pouvez. L'adresse de stockage du membre y est connue, qu'elle soit initialisée ou non. L'initialisation de la référence x(y) est donc légale.

0
S.M.