Есть ли в скобках после имени типа разница с новым?

862

Если "Тест" - обычный класс, есть ли разница между:

Test* test = new Test;

и

Test* test = new Test();
  • 1
    Это связано с (но не идентично) stackoverflow.com/questions/1613341/…
  • 0
    Просто используйте новый Test (), чтобы убедиться, что он инициализируется нулями
Теги:
initialization
constructor
new-operator
c++-faq

5 ответов

833
Лучший ответ

Позвольте получить педантичность, потому что есть различия, которые могут фактически повлиять на поведение вашего кода. Из комментариев, сделанных в статье "Old New Thing" , говорится следующее:

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

  • В С++ 1998 существует 2 типа инициализации: ноль и значение по умолчанию
  • В С++ 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() - zero-initialize

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

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

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

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

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

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

  • new B - default инициализирует (оставляет B:: m неинициализированным)

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

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

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

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

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

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

  • 0
    Для new C и new C() в C ++ 03 не инициализируется m ? Как насчет struct D { D() : {} int m; } (т.е. не POD из-за определенного пользователем ctor, но m не упоминается)?
  • 0
    Кажется, моя struct D упоминалась позже в этой ветке комментариев Old New Thing! И для new D и для new D() m не инициализируется.
Показать ещё 21 комментарий
53

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

Если используется в struct/class с определяемым пользователем конструктором, нет никакой разницы. Если вызывается тривиальная структура/класс (например, 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; vs new Thingy(); в этом случае изменилось между С++ 98 и С++ 2003. См. Объяснение Майкла Барра о том, как и почему.

19

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

Test t;      // create a Test called t

и

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

Это из-за базового правила С++ (и C): если что-то может быть объявлением, то это объявление.

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

  • 17
    Обратите внимание, что это особенно важный момент, потому что строка «Test t (5);» эквивалентно "Test t = Test (5);" - но "Test t ();" сильно отличается от "Test t = Test ();". +1
  • 9
    -1 Я не согласен с твоим утверждением, что вопросы можно игнорировать. Вам не нужно точно знать правила, но вы должны знать о них в случае, если вам нужно создать новый класс без определяемого пользователем конструктора по умолчанию (вам следует либо написать конструктор, либо поискать правила).
Показать ещё 7 комментариев
16

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

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

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

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

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

10

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню