web-dev-qa-db-fra.com

Pourquoi les membres const peuvent-ils être modifiés dans un constructeur?

Je suis curieux de savoir pourquoi les membres const peuvent être modifiés dans le constructeur.

Y a-t-il une règle standard dans l'initialisation qui remplace la "constance" d'un membre?

struct Bar {
    const int b = 5; // default member initialization
    Bar(int c):b(c) {}
};

Bar *b = new Bar(2); // Problem: Bar::b is modified to 2
                     // was expecting it to be an error

Des idées?

43
Joseph D.

Ce n'est pas une modification (ou une affectation) mais initialisation . par exemple.

struct Bar {
    const int b = 5; // initialization (via default member initializer)
    Bar(int c)
        :b(c)        // initialization (via member initializer list)
    {
        b = c;       // assignment; which is not allowed
    }
};

Le membre de données const ne peut pas être modifié ou affecté, mais il peut (et doit) être initialisé via la liste d'initialisation de membre ou l'initialiseur de membre par défaut.

Si l'initialiseur de membre par défaut et l'initialiseur de membre sont fournis sur le même membre de données, l'initialiseur de membre par défaut sera ignoré. Voilà pourquoi b->b est initialisé avec la valeur 2.

Si un membre a un initialiseur de membre par défaut et apparaît également dans la liste d'initialisation de membre dans un constructeur, l'initialiseur de membre par défaut est ignoré.

En revanche, l'initialiseur de membre par défaut prend effet uniquement lorsque le membre de données n'est pas spécifié dans la liste d'initialisation de membre. par exemple.

struct Bar {
    const int b = 5;   // default member initialization
    Bar(int c):b(c) {} // b is initialized with c
    Bar() {}           // b is initialized with 5
};
66
songyuanyao

Ajoutant à la grande réponse de songyuanyao, si vous voulez un membre de données const que vous ne pouvez pas initialiser dans un constructeur, vous pouvez rendre le membre static:

struct Bar {
    static const int b = 5; // static member initialization
    Bar(int c)
        :b(c)        // Error: static data member can only be initialized at its definition
    {
        b = c;       // Error: b is read-only
    }
};

En C++ 17, vous pouvez encore améliorer cela en le faisant inline:

struct Bar {
    inline static const int b = 5; // static member initialization
    Bar(int c)
        :b(c)        // Error: static data member can only be initialized at its definition
    {
        b = c;       // Error: b is read-only
    }
};

De cette façon, vous n'aurez aucun problème avec ODR.

16
Cássio Renan

Quand vous faites:

struct Bar {
    const int b = 5; // default member initialization
    ...
};

Vous dites au compilateur de le faire avec le constructeur par défaut:

...
Bar() : b(5) 
{}
...

Que vous ayez fourni ou non le constructeur par défaut. Lorsque vous fournissez le constructeur par défaut et l'affectation initiale, vous remplacez le code d'affectation par défaut du compilateur (c'est-à-dire b(5)). L'initialisation/affectation par défaut à la déclaration est utile lorsque vous avez plusieurs constructeurs et que vous pouvez ou non affecter les membres const dans tous les constructeurs:

...
Bar() = default; // b=5
Bar(int x) : b(x) // b=x
Bar(double y) : /*other init, but not b*/  // b=5
...
2
Ajay