web-dev-qa-db-fra.com

Les parenthèses après le nom du type font-elles une différence avec new?

Si 'Test' est une classe ordinaire, existe-t-il une différence entre:

Test* test = new Test;

et

Test* test = new Test();
956
David Read

Soyons pédants, car certaines différences peuvent réellement affecter le comportement de votre code. La plupart des éléments suivants sont tirés de commentaires faits dans un article "Old New Thing" .

Parfois, la mémoire renvoyée par le nouvel opérateur sera initialisée et parfois non, selon que le type que vous créez est un POD (données anciennes) , ou s'il s'agit d'une classe contient des membres POD et utilise un constructeur par défaut généré par le compilateur.

  • En C++ 1998, il existe 2 types d'initialisation: zéro et par défaut
  • En C++ 2003, un troisième type d'initialisation, initialisation de valeur, a été ajouté.

Présumer:

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

Dans un compilateur C++ 98, les événements suivants doivent se produire:

  • new A - valeur indéterminée
  • new A() - initialisation à zéro

  • new B - construction par défaut (B :: m n'est pas initialisé)

  • new B() - construction par défaut (B :: m n'est pas initialisé)

  • new C - construction par défaut (C :: m est initialisé à zéro)

  • new C() - construction par défaut (C :: m est initialisé à zéro)

Dans un compilateur conforme à C++ 03, les choses devraient fonctionner comme suit:

  • new A - valeur indéterminée
  • new A() - valeur-initialiser A, qui est une initialisation nulle puisqu'il s'agit d'un POD.

  • new B - default-initialise (laisse B :: m non initialisé)

  • new B() - valeur-initialise B qui initialise à zéro tous les champs puisque son ctor par défaut est un compilateur généré par opposition à celui défini par l'utilisateur.

  • new C - default-initialise C, qui appelle le ctor par défaut.

  • new C() - value-initialise C, qui appelle le ctor par défaut.

Donc, dans toutes les versions de C++, il y a une différence entre new A et new A(), car A est un POD.

Et il y a une différence de comportement entre C++ 98 et C++ 03 pour le cas new B().

C'est l'un des coins poussiéreux du C++ qui peut vous rendre fou. Lorsque vous construisez un objet, vous voulez parfois/avez besoin des parenthèses, parfois vous ne pouvez absolument pas les avoir et parfois cela n’a pas d’importance.

916
Michael Burr

new Thing(); indique explicitement que vous voulez un constructeur appelé alors que new Thing; signifie que vous ne voulez pas que le constructeur ne soit pas appelé.

Si utilisé sur une structure/classe avec un constructeur défini par l'utilisateur, il n'y a pas de différence. Si elle est appelée sur une structure/classe triviale (par exemple, struct Thing { int i; };), alors new Thing; ressemble à malloc(sizeof(Thing)); alors que new Thing(); ressemble à calloc(sizeof(Thing)); - il est initialisé à zéro.

Le piège se situe entre:

struct Thingy {
  ~Thingy(); // No-longer a trivial class
  virtual WaxOn();
  int i;
};

Le comportement de new Thingy; vs new Thingy(); dans ce cas a changé entre C++ 98 et C++ 2003. Voir l'explication de Michael Burr pour savoir comment et pourquoi.

58
kfsone

En général, nous avons l'initialisation par défaut dans le premier cas et l'initialisation de la valeur dans le second cas.

Par exemple: en cas de int (type POD):

  • int* test = new int - nous avons n'importe quelle initialisation et la valeur de * test peut être n'importe laquelle.

  • int* test = new int() - * test aura la valeur 0.

le comportement suivant dépend de votre test de type. Nous avons des cas différents: test avec constructeur defult, test avec constructeur généré par défaut, test contenant un membre POD, non membre POD ...

17
bayda

Non, ce sont les mêmes. Mais il y a une différence entre:

Test t;      // create a Test called t

et

Test t();   // declare a function called t which returns a Test

Ceci est dû à la règle de base C++ (et C): Si quelque chose peut éventuellement être une déclaration, il s'agit d'une déclaration.

Edit: Concernant les problèmes d’initialisation concernant les données POD et non-POD, bien que je souscrive à tout ce qui a été dit, je voudrais simplement souligner que ces problèmes ne s’appliquent que si la chose est nouvelle ou autrement construit n'a pas de constructeur défini par l'utilisateur. S'il existe un tel constructeur, il sera utilisé. Un tel constructeur existe pour 99,99% des classes conçues de manière judicieuse, ce qui permet d'ignorer les problèmes.

16
anon

En supposant que Test soit une classe avec un constructeur défini, il n'y a pas de différence. La dernière forme rend un peu plus clair que le constructeur de Test est en cours d'exécution, mais c'est à peu près tout.

10
Evan Shaw