2009-03-06 6 views
860

Jeśli 'test' jest zwykłym klasy, jest jakaś różnica pomiędzy:Czy nawiasy po nazwie typu różnią się od nowego?

Test* test = new Test; 

i

Test* test = new Test(); 
+1

Jest to związane (ale nie to samo) z http://stackoverflow.com/questions/1613341/what-do-the-following-phrases-mean-in-c-zero-default-and-value-initializati –

+0

Wystarczy użyć nowego testu(), aby upewnić się, że jest on zainicjowany na zero. – Sung

Odpowiedz

836

Chodźmy pedantycznie, ponieważ istnieją różnice, które mogą wpływać na zachowanie twojego kodu. Wiele z poniższych informacji zaczerpnięto z komentarzy do pliku "Old New Thing" article.

Czasami pamięć zwrócona przez nowego operatora zostanie zainicjowana, a czasami nie będzie zależna od tego, czy tworzony typ to POD (plain old data), czy jest to klasa zawierająca elementy POD i używająca kompilatora generowany domyślny konstruktor.

  • W C++ 1998 są 2 typy inicjalizacji: zero i domyślne
  • W C++ 2003 3rd rodzaj inicjalizacji inicjalizacji wartość dodano.

Załóżmy:

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 

W C++ 98 kompilator następujące powinny wystąpić:

  • new A - wartość nieokreśloną
  • new A() - bez konieczności zainicjowania

  • new B - domyślny konstrukt (B :: m oznacza niezainicjowanego)

  • new B() - domyślny konstrukt (B :: m oznacza niezainicjowanego)

  • new C - domyślny konstrukt (C :: m oznacza zero zainicjowany)

  • new C() - default konstrukt (C :: m oznacza zero zainicjowany)

W C++ 03 zgodnym kompilatora, wszystko powinno działać tak:

  • new A - wartość nieokreślona
  • new A() - wartości inicjalizacji, który jest zero-inicjalizacji ponieważ jest to POD.

  • new B - default-inicjuje (liście B :: m niezainicjowanej)

  • new B() - wartość inicjuje B, które zerowej inicjuje wszystkie pola, ponieważ jego domyślny konstruktor jest kompilator generowane w przeciwieństwie do zdefiniowanego przez użytkownika.

  • new C - domyślnie-inicjalizuje C, który wywołuje domyślny ctor.

  • new C() - wartość-inicjuje C, wywołując domyślny ctor.

Tak więc we wszystkich wersjach C++ istnieje różnica między new A a new A(), ponieważ A to POD.

Istnieje różnica w zachowaniu między C++ 98 i C++ 03 dla sprawy new B().

To jeden z zakurzonych zakamarków C++, który może doprowadzić do szaleństwa. Podczas konstruowania obiektu czasami potrzebujesz/potrzebujesz paren, czasami absolutnie nie możesz ich mieć, a czasami to nie ma znaczenia.

+0

Dla 'new C' i' new C() 'w C++ 03, czy' m' pozostało niezainicjalizowane? A co powiesz na 'struct D {D(): {} int m; } '(tj. nie-POD z powodu ctor zdefiniowanego przez użytkownika, ale m nie jest wymienione)? –

+0

Wydaje się, że moja 'struct D' została wspomniana później w tym wątku komentarza Old New Thing! Zarówno dla 'new D', jak i' new D() ',' m' nie jest inicjowane. –

+4

@j_random_hacker, 'new A()' domyślnie zainicjuje obiekt w C++ 98, tak jak robi to z 'new B()', 'new B',' new C() 'and' new C', ale * nie * z 'nowym A'. Oznacza to, że domyślna inicjalizacja jest zawsze wykonywana w C++ 98, gdy: 1) Klasa jest non-POD i brak inicjalizatora, lub 2) Inicjatorem jest '()'. default-initialization zero - inicjalizuje obiekt, jeśli jest to POD, ale wywołuje domyślny konstruktor dla nie-POD. –

15

Nie, one są takie same. Ale jest różnica pomiędzy:

Test t;  // create a Test called t 

i

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

Wynika to z podstawowej C++ (i C) zasada: Jeśli coś może być ewentualnie oświadczenie, to jest deklaracja.

Edit: Re zagadnień dotyczących POD inicjalizacji i danych non-Pod, natomiast zgadzam się ze wszystkim, co zostało powiedziane, chciałbym tylko zwrócić uwagę, że tylko te kwestie zastosowania, jeżeli rzecz jest new'd lub w przeciwnym razie nie ma konstruktora zdefiniowanego przez użytkownika. Jeśli istnieje taki konstruktor, będzie on użyty. Dla 99,99% rozsądnie zaprojektowanych klas będzie taki konstruktor, a więc problemy mogą zostać zignorowane.

+17

Należy zauważyć, że jest to szczególnie ważny punkt, ponieważ wiersz "Test t (5);" jest równoważne "Test t = Test (5);" - ale "Przetestuj t();" różni się bardzo od "Test t = Test();". +1 – ojrac

+9

-1 Nie zgadzam się z twoim stwierdzeniem, że problemy można zignorować. Nie musisz dokładnie znać reguł, ale powinieneś być tego świadomy na wypadek, gdybyś musiał stworzyć nową klasę bez domyślnego konstruktora zdefiniowanego przez użytkownika (powinieneś wtedy albo napisać konstruktor, albo wyszukać reguły). – avakar

+10

-1 dla znanej niepoprawnej odpowiedzi. Twoja edycja ignoruje obecność kodu napisanego przez byłych programistów C, którzy nie rozumieją/nie używają konstruktorów. – Tom

10

Zakładając, że test jest klasą o zdefiniowanym konstruktorze, nie ma różnicy. Ta ostatnia forma sprawia, że ​​trochę bardziej oczywiste jest, że konstruktor Testa działa, ale to już wszystko.

15

Generalnie mamy domyślną inicjalizację w pierwszym przypadku, a inicjowanie wartości w drugim przypadku.

Na przykład: w przypadku z int (typu POD):

  • int* test = new int - mamy żadnej inicjalizacji i wartość * testu może być dowolny.

  • int* test = new int() - * test będzie miał wartość 0.

Następne zachowanie zależy od typu testu. Mamy następujące przypadki: test ma konstruktor defult, Test wygenerował konstruktora domyślnego, Test zawiera element POD, członek non POD ...

44

new Thing(); jest wyraźny, że chcesz wywołać konstruktora, podczas gdy new Thing; przyjmuje się, że nie masz nic przeciwko, jeśli konstruktor nie zostanie wywołany.

W przypadku użycia w struct/class z konstruktorem zdefiniowanym przez użytkownika nie ma różnicy. Jeśli wywoływana jest na trywialną strukturę/klasę (np. struct Thing { int i; };), wówczas new Thing; jest jak malloc(sizeof(Thing));, podczas gdy new Thing(); jest jak calloc(sizeof(Thing)); - inicjuje zero.

haczyka leży poza zakresem:

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

zachowanie new Thingy; vs new Thingy(); w tej sprawie zmieniło między C++ 98 i C++ 2003. Zobacz wyjaśnienie Michaela Burra, jak i dlaczego.

Powiązane problemy