2009-03-06 3 views
860

Если 'Test' представляет собой обычный класс, есть ли разница между:Составляются ли скобки после названия типа с новым?

Test* test = new Test; 

и

Test* test = new Test(); 
+1

Это связано с (но не идентичным) http://stackoverflow.com/questions/1613341/what-do-the-following-phrases-mean-in-c-zero-default-and-value-initializati –

+0

Просто используйте новый тест(), чтобы убедиться, что он инициализирован нулем. – Sung

ответ

836

Давайте сделаем педантичным, потому что есть различия, которые могут действительно повлиять на поведение вашего кода. Из комментариев, сделанных к "Old New Thing" article, взята значительная часть.

Иногда память, возвращаемая новым оператором, будет инициализирована, и иногда она не зависит от того, является ли тип, который вы новичок, POD (plain old data), или если это класс, который содержит элементы POD и использует компилятор -генерированный конструктор по умолчанию.

  • В C++ 1998 существует 2 вида инициализации: ноль и по умолчанию
  • В C++ 2003 третий тип инициализации, была добавлена ​​инициализация значения.

Предположим:

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 

В С ++ 98 компилятор в следующее должно произойти:

  • new A - неопределенное значение
  • new A() - нуль-инициализации

  • new B - конструкция по умолчанию (Б :: м не инициализирован)

  • new B() - по умолчанию конструкция (Б :: м не инициализирован)

  • new C - конструкция по умолчанию (C :: м равна нулю инициализирован)

  • new C() - конструкт по умолчанию (C :: м равен нулю инициализирован)

В C++ 03 компилятор с совместимой, все должно работать так:

  • new A - неопределенное значение
  • new A() - значение инициализации A, которая является нулевой инициализации, так как это стручка.

  • new B - по умолчанию инициализирует (уходит B :: м) неинициализированного

  • new B() - значение инициализирует В, который нулевой инициализирует все поля, так как его по умолчанию является т е р компилятора, в отличие от определяемого пользователя.

  • new C - по умолчанию инициализирует C, который вызывает значение по умолчанию ctor.

  • new C() - значение инициализирует C, который вызывает значение по умолчанию ctor.

Так во всех версиях C++ есть разница между new A и new A(), потому что А является POD.

И есть разница в поведении между C++ 98 и C++ 03 для случая new B().

Это один из пыльных уголков C++, который может свести вас с ума. Когда вы строите объект, иногда вам нужны/нужны парнеры, иногда вы их абсолютно не можете, и иногда это не имеет значения.

+0

Для 'new C' и' new C() 'под C++ 03,' m' осталось неинициализированным? Как насчет 'struct D {D(): {} int m; } '(т. е. не-POD из-за пользовательского ctor, но m не упоминается)? –

+0

Кажется, что моя 'struct D' была упомянута позже в этой ветке« New New Thing »! Для «новых D» и «новых D()', 'm' не инициализируется. –

+4

@j_random_hacker, 'new A()' будет по умолчанию инициализировать объект в C++ 98, как это происходит с помощью 'new B()', 'new B',' new C() 'и' new C', но * не * с 'новым A'. То есть инициализация по умолчанию всегда выполняется в C++ 98, если: 1) класс является не-POD, а инициализатор отсутствует, или 2) инициализатором является '()'. default-initialization zero - инициализирует объект, если это POD, но вызывает конструктор по умолчанию для не-POD. –

15

Нет, они одинаковы. Но есть разница между:

Test t;  // create a Test called t 

и

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

Это происходит потому, что основной C++ (и C) правила: Если что-то может быть возможно заявление, то это заявление.

Edit: Re вопросов, касающихся инициализации POD и не-POD данных, в то время как я согласен со всем, что было сказано, я просто хотел бы отметить, что эти вопросы относятся только если вещь быть new'd или иначе построенный не имеет определяемого пользователем конструктора. Если есть такой конструктор, он будет использоваться. Для 99,99% разумно спроектированных классов будет такой конструктор, и поэтому проблемы могут быть проигнорированы.

+17

Обратите внимание, что это особенно важный момент, потому что строка «Test t (5)»; эквивалентно «Test t = Test (5)»; - но «Test t()»; очень отличается от «Test t = Test();». +1 – ojrac

+9

-1, я не согласен с вашим утверждением, что проблемы можно игнорировать. Вам не обязательно знать правила точно, но вы должны знать о них, если вам нужно создать новый класс без пользовательского конструктора по умолчанию (вы должны либо написать конструктор, либо найти правила). – avakar

+10

-1 для известного неверного ответа. Ваш Редактор игнорирует наличие кода, написанного бывшими программистами C, которые не понимали/не использовали конструкторы. – Tom

10

Предполагая, что Test является классом с определенным конструктором, нет никакой разницы. Последняя форма немного упрощает конструктор Test, но это все.

15

В общем случае мы инициализируем по умолчанию в первом случае и инициализацию значения во втором случае.

Например: в случае с INT (типа POD):

  • int* test = new int - мы инициализацию и значение * теста может быть любым.

  • int* test = new int() - * тест будет иметь значение 0.

следующее поведение зависит от типа теста. У нас есть дефференциальные случаи: Test имеет конструктор defult, Test создал конструктор по умолчанию, Test содержит член POD, член не POD ...

44

new Thing(); явно указано, что вы хотите, чтобы вызываемый конструктор вызывался, а new Thing; - подразумевается, что вы не возражаете, если конструктор не вызван.

Если используется для структуры/класса с определяемым пользователем конструктором, нет никакой разницы. Если вызывается тривиальная структура/класс (например, struct Thing { int i; };), то new Thing; соответствует malloc(sizeof(Thing));, тогда как new Thing(); соответствует calloc(sizeof(Thing)); - он получает нулевой инициализированный.

Гоча лежит в промежутке между:

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

Поведение new Thingy; против new Thingy(); в этом случае изменяется между C++ 98 и C++ 2003. См. Объяснение Майкла Барра о том, как и почему.