web-dev-qa-db-fra.com

C ++ utilise toujours un constructeur explicite

Après avoir lu le blog suivant:

http://xania.org/200711/ambiguous-overloading

J'ai commencé à me demander "ne devrais-je pas toujours définir explicitement mes constructeurs?"

J'ai donc commencé à lire plus que découvert cet article:

http://www.sjbrown.co.uk/2004/05/01/always-use-explicit/

Ce qui montre un autre exemple et explique également ses pensées derrière. Mais bien sûr, c'est la pensée d'un blogueur.

Je serais heureux d'entendre certains d'entre vous, ce que vous pensez de la manière, quelle est votre expérience avec le sujet et quelques exemples pour les deux seraient Nice.

35
oopsi

La sagesse traditionnelle est que les constructeurs en prenant un paramètre (explicitement ou efficacement en utilisant des paramètres par défaut) doivent être marqués explicit, sauf s'ils définissent une conversion (std::string convertible de const char* en étant un exemple). Vous en avez vous-même compris les raisons, car les conversions implicites peuvent en effet rendre la vie plus difficile qu'elle ne doit l'être.

Une exception peut-être évidente à cela serait le constructeur de copie. Ou peut-être une autre façon est de considérer que la plupart des types sont convertibles de et vers eux-mêmes, et qu'en tant que tel, le constructeur de copie n'est pas marqué explicit la plupart du temps.

Bien qu'il puisse sembler que le marquage de tous les autres types de constructeurs explicit ne fait pas de mal, je m'y opposerais. Parce que tandis que explicit n'a aucun effet sur un constructeur prenant plusieurs arguments en C++ 03, il a un effet en C++ 11. Pour le mettre en code:

struct foo {
    explicit foo(int i);
    foo(int i, int j);
    explicit foo(int i, int j, int k);
};

foo make_foo()
{
    /* Not C++11-specific: */
    // Error: no conversion from int to foo
    return 42;

    // Okay: construction, not conversion
    return foo(42);

    // Okay: constructions
    return foo(42, 42);
    return foo(42, 42, 42);

    /* C++11 specific: */
    // Error: no conversion from int to foo
    return { 42 };

    // Not an error, not a conversion
    return { 42, 42 };

    // Error! Constructor is explicit
    return { 42, 42, 42 };
    // Not an error, direct-initialization syntax
    return foo { 42, 42, 42 };
}

Personnellement, je trouve inutilement verbeux que dans une fonction qui renvoie foo je dois retourner explicitement foo { 42, 42, 42 }. Je ne vois pas de quoi explicit me protège. Je veux vraiment le { initializers... } syntaxe pour signifier 'construire un objet à partir d'initialiseurs donnés', et explicit se met en travers de cela tout en me sauvant de rien. (Puisque { i } se résume à i dans le contexte de la copie-initialisation - la plupart du temps - je renoncerai volontiers à celle-ci.)

Je dirais donc prendre l'habitude d'utiliser explicit pour les constructeurs unaires, et ceux-là seulement.

57
Luc Danton