Question Est-ce que les parenthèses après le nom du type font une différence avec new?


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

Test* test = new Test;

et

Test* test = new Test();

891
2018-03-06 19:39


origine


Réponses:


Faisons un pédantisme, car il y a des différences qui peuvent affecter le comportement de votre code. Une grande partie de ce qui suit est tirée des commentaires faits à "Old New Thing" article.

Parfois la mémoire retournée par le nouvel opérateur sera initialisée, et parfois cela ne dépendra pas si le type que vous créez est un POD (données anciennes simples)ou si c'est une classe qui contient des membres POD et utilise un constructeur par défaut généré par le compilateur.

  • En C ++ 1998 il y a 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é.

Assumer:

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 éléments suivants doivent se produire:

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

  • new B   - construit par défaut (B :: m est non initialisé)

  • new B() - construit par défaut (B :: m est non initialisé)

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

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

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

  • new A    - valeur indéterminée
  • new A()  - value-initialize A, qui est une initialisation zéro puisque c'est un POD.

  • new B    - default-initializes (quitte B :: m non initialisé)

  • new B()  - value-initialise B qui initialise zéro tous les champs puisque son ctor par défaut est un compilateur généré par opposition à 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() parce que 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 de C ++ qui peut vous rendre fou. Lors de la construction d'un objet, parfois vous voulez / avez besoin des parens, parfois vous ne pouvez absolument pas les avoir, et parfois cela n'a pas d'importance.


860
2018-03-06 21:01



new Thing(); est explicite que vous voulez un constructeur appelé alors new Thing; est pris pour impliquer que cela ne vous dérange pas si le constructeur n'est pas appelé.

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

Le gotcha se situe entre:

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

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


49
2018-02-15 19:57



Non, ils 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

C'est à cause de la règle de base C ++ (et C): Si quelque chose peut éventuellement être une déclaration, alors c'est une déclaration.

Modifier: En ce qui concerne les problèmes d'initialisation concernant les données POD et non POD, même si je suis d'accord avec tout ce qui a été dit, je voudrais juste souligner que ces problèmes ne s'appliquent que si l'objet neuf ou construit n'a pas d'utilisateur. constructeur défini. S'il existe un tel constructeur, il sera utilisé. Pour 99,99% des classes raisonnablement conçues, il y aura un tel constructeur, et donc les problèmes peuvent être ignorés.


16
2018-03-06 19:42



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

Par exemple: dans le cas avec int (type POD):

  • int* test = new int - nous avons toute initialisation et la valeur de * test peut être tout.

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

le comportement suivant dépendait de votre test de type. Nous avons des cas defferent: Test ont un constructeur defult, Test ont généré un constructeur par défaut, Test contiennent un membre POD, un membre non POD ...


16
2018-03-06 20:00



En supposant que Test est 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
2018-03-06 19:42