Será que os parênteses após o nome do tipo fazer a diferença com o novo?
-
03-07-2019 - |
Pergunta
Se 'Test' é uma classe comum, não há qualquer diferença entre:
Test* test = new Test;
e
Test* test = new Test();
Solução
Vamos get pedante, porque existem diferenças que podem realmente afetar o comportamento do seu código. Grande parte da seguinte é retirado de comentários feitos a um "Old New Thing "Artigo .
Às vezes a memória devolvida pelo novo operador será inicializado, e às vezes não, dependendo se o tipo que você está Newing up é um POD (plain dados antigos) , ou se é uma classe que contém membros POD e está usando um construtor padrão gerado pelo compilador.
- Em C ++ 1998, existem 2 tipos de inicialização: zero e padrão
- Em C ++ 2003, um 3º tipo de inicialização, inicialização valor foi adicionado.
Suponha:
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
Num C ++ 98 compilador, o seguinte deve ocorrer:
-
new A
- valor indeterminado -
new A()
- zero initialize -
new B
- construo padrão (B :: m é inicializado) -
new B()
- construo padrão (B :: m é inicializado) -
new C
- construo padrão (C :: m é inicializado para zero) -
new C()
- construo padrão (C :: m é inicializado para zero)
Em um C ++ 03 compilador conformant, as coisas devem funcionar assim:
-
new A
- valor indeterminado -
new A()
-. Um valor-initialize, que é zero-inicialização já que é um POD -
new B
- default-inicializa (folhas B :: m inicializado) -
new B()
-. Value-inicializa B que zero inicializa todos os campos, desde a sua ctor padrão é compilador gerado em oposição a definida pelo usuário -
new C
-. Default-inicializa C, que chama o ctor padrão -
new C()
-. Value-inicializa C, que chama o ctor padrão
Assim, em todas as versões do C ++ há uma diferença entre new A
e new A()
porque A é um POD.
E há uma diferença de comportamento entre C ++ 98 e C ++ 03 para o caso new B()
.
Este é um dos cantos empoeirados de C ++ que pode deixá-lo louco. Ao construir um objeto, às vezes você quer / precisa dos parênteses, às vezes você absolutamente não pode tê-los, e às vezes não importa.
Outras dicas
new Thing();
é explícito que deseja um construtor chamado enquanto new Thing;
é levado para implica que você não se importa se o construtor não é chamado.
Se usado em uma struct / classe com um construtor definido pelo usuário, não há diferença. Se chamado em um struct trivial / aula (por exemplo struct Thing { int i; };
), então new Thing;
é como malloc(sizeof(Thing));
enquanto new Thing();
é como calloc(sizeof(Thing));
-. Ele recebe de zero inicializado
As mentiras pegadinha no meio:
struct Thingy {
~Thingy(); // No-longer a trivial class
virtual WaxOn();
int i;
};
O comportamento do new Thingy;
vs new Thingy();
neste caso mudou entre C ++ 98 e C ++ 2003. Veja a explicação de Michael Burr para como e porquê.
Não, eles são os mesmos. Mas há uma diferença entre:
Test t; // create a Test called t
e
Test t(); // declare a function called t which returns a Test
Este é por causa do C ++ básico (e C) regra:. Se algo pode eventualmente ser uma declaração, então é uma declaração
Editar: Re os problemas de inicialização em relação a POD e dados não-POD, enquanto eu concordo com tudo o que tem sido dito, eu gostaria apenas de salientar que estas questões só se aplicam se a coisa ser new'd ou de outro modo construído não tem um construtor definido pelo utilizador. Se houver tal um construtor será usado. Para 99,99% das aulas de forma sensata projetados haverá tal construtor, e assim os problemas podem ser ignorados.
Em geral temos default-inicialização no primeiro caso e de valor de inicialização no segundo caso.
Por exemplo: no caso com int (tipo POD):
-
int* test = new int
-. Temos qualquer inicialização eo valor do teste * pode ser qualquer -
int* test = new int()
-. Test * terá valor 0
próxima comportamento dependia do seu tipo de teste. Temos casos defferent: Teste tem construtor padrão construtor defult, teste geraram, Teste conter membro do POD, membro não POD ...
Assumindo que o teste é uma classe com um construtor definido, não há nenhuma diferença. Esta última forma torna um pouco mais claro que o construtor de teste está sendo executado, mas que é sobre ele.