initialisation: parenthèse vs signe égal [dupliquer]

Doublon Possible:
y a-t-il une différence en C++ entre l'initialisation de la copie et l'initialisation de l'affectation?

Quelle est la différence entre

T a(b);

Et

T a = b;

Et

T a = T(b);

?

33
demandé sur Community 2010-12-17 15:42:53

4 réponses

T a( b );

Est initialisation directe , à moins qu'il n'analyse comme une déclaration de fonction, auquel cas il s'agit d'une déclaration de fonction.

T a = b;

Est copie d'initialisation, ce qui signifie qu'il fonctionne comme si un objet temporaire est construit sur le côté droit, et que a est ensuite copier construits ou, en C++11 et, plus tard, éventuellement déplacer construit, depuis que temporaire.

Le compilateur est libre d'éluder (supprimer) le temporaire+copier/déplacer chaque fois qu'il le peut, mais un constructeur copy ou move, selon ce qui serait logiquement utilisé, doit toujours être accessible et non explicit.

Par exemple, en C++03, vous ne pouvez pas copier-initialiser un std::ostringstream, car il n'a pas de constructeur de copie. En C++11, Vous pouvez copier-initialiser un ostringstream Si l'initialiseur EST TEMPORAIRE, Ce qui entraîne une construction de déplacement logique (qui sera cependant généralement élidée, optimisée). Par exemple, cette déclaration d'initialisation de copie,

ostringstream s = ostringstream( "blah" );

... ne compile pas comme C++03, car en C++03, l'initialisation de la copie appelle le constructeur de copie de la classe, qui n'existe pas. Il compile cependant en C++11, car en C++11, l'initialisation de la copie appelle le constructeur move. Et alors que (pour maintenir son illusion d'être un flux) un std::ostringstream ne peut pas être directement copié, il peut être déplacé.

Une autre différence: en C++03, seule la syntaxe d'initialisation de copie prend en charge accolades initializer, que vous pouvez utiliser en C++03 lorsque T est un type d'agrégat tel qu'un tableau brut. En C++11, la notation des accolades a été étendue et généralisée en tant que syntaxe d'initialisation uniforme , de sorte qu'elle peut également être utilisée avec l'initialisation directe. Et donc la déclaration d'initialisation directe suivante,

int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };

... ne compile pas en C++03, mais compile en C++11 et versions ultérieures.

La syntaxe d'initialisation de copie = est la syntaxe d'initialisation d'origine de C.

Et en C++11 et plus tard, en raison de déplacer la sémantique, il peut être utilisé dans un éventail beaucoup plus large de cas qu'en C++03, comme avec un std::ostringstream.

24
répondu Cheers and hth. - Alf 2016-07-10 20:36:49
T a(b);

Appelle un constructeur de a qui accepte b. (Si b est du même type, alors le constructeur de copie est appelé).

T a = b;

Un objet temporaire de type T est créé pour être construit par b. Ensuite, le constructeur de copie est appelé(= n'est pas une affectation dans ce cas et le cas suivant!).

T a = T(b);

Comme ci-dessus! sauf que nous avons explicitement construit un objet temporaire.

Notez que la norme permet l'élimination totale des copies temporaires dans le deuxième et le troisième cas. Aussi, si b n'est pas de type T, puis dans le premier cas, T n'ont pas besoin d'avoir un constructeur de copie. Dans les deuxième et troisième cas, même si l'implémentation est libre d'optimiser le tout, elle nécessite toujours un constructeur de copie accessible. IIRC la norme appelle cela: copie élision.

18
répondu AraK 2010-12-17 13:00:17

Ce sont tous des appels de constructeur - le signe = est juste du sucre syntaxique. Exactement quels constructeurs sont appelés est dans une certaine mesure jusqu'au compilateur.

0
répondu unquiet mind 2010-12-17 12:56:23

L'opérateur = appellera le constructeur de copie par défaut sauf si l'opérateur = est surchargé je crois... cela ferait une copie superficielle; assigner les mêmes valeurs de membre au premier objet en tant qu'opérateur de droite

-3
répondu oldSkool 2010-12-17 12:46:07