c++ puntuación - ¿Los paréntesis después del nombre de tipo hacen una diferencia con el nuevo?




interrogación signos (5)

Vayamos pedantes, porque hay diferencias que pueden afectar el comportamiento de su código. Gran parte de lo siguiente está tomado de los comentarios hechos a un artículo de "Old New Thing" .

A veces, la memoria devuelta por el nuevo operador se inicializará, y otras veces no dependiendo de si el tipo que está actualizando es un POD (datos antiguos) , o si es una clase que contiene miembros de POD y está usando una constructor por defecto generado por el compilador.

  • En C ++ 1998 hay 2 tipos de inicialización: cero y por defecto
  • En C ++ 2003 se agregó un tercer tipo de inicialización, la inicialización de valores.

Asumir:

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

En un compilador de C ++ 98, debería ocurrir lo siguiente:

  • new A - valor indeterminado
  • new A() - inicializar cero

  • new B - construcción por defecto (B :: m no está inicializada)

  • new B() : construcción predeterminada (B :: m no está inicializada)

  • new C - construcción por defecto (C :: m es cero inicializada)

  • new C() - construcción por defecto (C :: m es cero inicializada)

En un compilador conforme a C ++ 03, las cosas deberían funcionar así:

  • new A - valor indeterminado
  • new A() - value-initialize A, que es cero inicialización ya que es un POD.

  • new B - inicializa por defecto (deja B :: m sin inicializar)

  • new B() : el valor inicializa B, que inicializa en cero todos los campos, ya que su ctor predeterminado se genera por compilador en lugar de definido por el usuario.

  • new C - default-initializes C, que llama al ctor predeterminado.

  • new C() : el valor inicializa C, que llama al ctor predeterminado.

Entonces, en todas las versiones de C ++ hay una diferencia entre la new A y la new A() porque A es un POD.

Y hay una diferencia de comportamiento entre C ++ 98 y C ++ 03 para el caso new B() .

Este es uno de los rincones polvorientos de C ++ que pueden volverte loco. Cuando construyes un objeto, a veces quieres o necesitas los paréns, a veces no puedes tenerlos y otras no importa.

Si 'Test' es una clase ordinaria, ¿hay alguna diferencia entre:

Test* test = new Test;

y

Test* test = new Test();

No ellos son los mismos. Pero hay una diferencia entre:

Test t;      // create a Test called t

y

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

Esto se debe a la regla básica de C ++ (y C): si algo puede ser una declaración, entonces es una declaración.

Edit: Con respecto a los problemas de inicialización relacionados con los datos POD y no POD, aunque estoy de acuerdo con todo lo que se ha dicho, me gustaría señalar que estos problemas solo se aplican si el hecho de ser nuevo o construido no tiene una constructor definido por el usuario. Si existe tal constructor será utilizado. Para el 99,99% de las clases diseñadas sensiblemente, habrá un constructor de este tipo, por lo que los problemas pueden ignorarse.


new Thing(); Es explícito que quieres un constructor llamado While new Thing; se supone que no te importa si el constructor no es llamado.

Si se utiliza en una estructura / clase con un constructor definido por el usuario, no hay diferencia. Si se invoca en una estructura / clase trivial (por ejemplo, struct Thing { int i; }; ), entonces new Thing; es como malloc(sizeof(Thing)); mientras que new Thing(); es como calloc(sizeof(Thing)); - Obtiene cero inicializado.

El gotcha se encuentra en el medio

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

El comportamiento de la new Thingy; vs new Thingy(); en este caso cambió entre C ++ 98 y C ++ 2003. Vea la explicación de Michael Burr sobre cómo y por qué.


En general, tenemos inicialización predeterminada en el primer caso e inicialización de valor en el segundo caso.

Por ejemplo: en caso de int (tipo POD):

  • int* test = new int - tenemos cualquier inicialización y el valor de * test puede ser cualquiera.

  • int* test = new int() - * test tendrá 0 valores.

El siguiente comportamiento depende de tu tipo Test. Tenemos diferentes casos: la prueba tiene constructor defectuoso, la prueba ha generado el constructor predeterminado, la prueba contiene miembro POD, no miembro POD ...


No se puede utilizar la declaración hacia adelante con la estructura typedef.

La estructura en sí es un tipo anónimo, por lo que no tiene un nombre real para reenviar declarar.

typedef struct{
    int one;
    int two;
}myStruct;

Una declaración hacia adelante como esta no funcionará:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types




c++ constructor initialization new-operator c++-faq