Влияют ли скобки после имени типа в операторе new на инициализацию?
Ключевое различие: инициализация по умолчанию vs. value-инициализация
Да, скобки после имени типа в new имеют принципиальное значение. Разница заключается в двух разных видах инициализации:
- Без скобок (
new int) — инициализация по умолчанию (default initialization). - Со скобками (
new int()) — value-инициализация (value initialization).
Для встроенных типов (int, char, double и т.д.)
Это самый важный случай, который вы заметили:
int* p1 = new int; // Значение *p1 НЕОПРЕДЕЛЕНО (мусор)
int* p2 = new int(); // Значение *p2 гарантированно равно 0
Почему так? Правила C++ гласят:
- Инициализация по умолчанию для встроенных типов не выполняет никакой инициализации. В памяти остаётся то, что там было раньше (мусор).
- Value-инициализация для встроенных типов обнуляет их (zero-initialization). Для
intэто 0, дляbool—false, дляdouble— 0.0.
Для классов с определённым конструктором по умолчанию
Если у класса есть конструктор по умолчанию (без параметров), то разницы нет — в обоих случаях будет вызван этот конструктор:
class MyClass {
public:
MyClass() { std::cout << "Constructor called\n"; }
};
MyClass* obj1 = new MyClass; // Вызовет конструктор
MyClass* obj2 = new MyClass();// Тоже вызовет конструктор
Оба варианта ведут себя одинаково.
Для классов без конструктора по умолчанию
Здесь разница может быть критичной. Если у класса нет конструктора по умолчанию:
class MyClass {
public:
MyClass(int x) {} // Только конструктор с параметром
};
MyClass* obj1 = new MyClass; // ОШИБКА компиляции!
MyClass* obj2 = new MyClass(); // ОШИБКА компиляции!
Оба варианта не скомпилируются, так как компилятор не может сгенерировать конструктор по умолчанию.
Для классов с тривиальным конструктором (POD-типы)
Если класс — это агрегат (например, struct без пользовательских конструкторов):
struct Point {
int x;
int y;
};
Point* p1 = new Point; // x и y НЕ инициализированы (мусор)
Point* p2 = new Point(); // x и y обнулены (0, 0)
Здесь снова проявляется разница: без скобок — мусор, со скобками — обнуление всех полей.
Явная инициализация: new int(42)
Когда вы пишете new int(42) или new MyClass("hello") — это прямая инициализация (direct initialization). Скобки здесь используются для передачи аргументов конструктору. Это не то же самое, что пустые скобки. new int(42) создаст int со значением 42.
Рекомендация
Для встроенных типов и POD-структур всегда используйте new T() (с пустыми скобками), чтобы избежать неопределённого поведения из-за мусора в памяти. Для классов с конструктором по умолчанию разницы нет, но для единообразия многие разработчики пишут new Class().
Важно: В современном C++ (C++11 и новее) предпочтительнее использовать умные указатели (std::unique_ptr, std::make_unique) и контейнеры STL, чтобы избежать ручного управления памятью. std::make_unique<int>() всегда выполняет value-инициализацию (обнуление).
Дополнение: списки инициализации в C++11
В C++11 появился ещё один синтаксис — uniform initialization (универсальная инициализация) с фигурными скобками:
int* p = new int{}; // Value-инициализация, *p = 0
int* q = new int{42}; // Прямая инициализация, *q = 42
Point* pt = new Point{10, 20}; // Агрегатная инициализация
Этот синтаксис работает одинаково для всех типов и часто считается более безопасным, так как он предотвращает most vexing parse (самую неприятную проблему синтаксического анализа C++).
Сравните:
MyClass obj(); // Ошибка! Это объявление функции, а не объекта!
MyClass obj{}; // OK, создание объекта с value-инициализацией
Поэтому в современном коде часто рекомендуют использовать фигурные скобки для инициализации. Однако для new это работает так же, как и круглые скобки: new int{} — это value-инициализация (обнуление), а new int — инициализация по умолчанию (мусор).
Итог: если вы хотите гарантированно обнулить память при выделении через new, используйте new T() или new T{}. Без скобок полагайтесь на то, что компилятор оставит мусор для встроенных типов.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги