<MyRusakov.ru />

Разработчик игр на Unreal Engine

Разработчик игр на Unreal Engine

Этот комплект с нуля всего за 7 месяцев сделает Вас Unreal-разработчиком. И при этом учиться достаточно 1 час в день.

Начнёте Вы с основ программирования, постепенно перейдя к C++. Затем очень подробно изучите Unreal Engine, и после научитесь программировать на C++ в Unreal Engine. В конце создадите крупный проект на C++ в Unreal Engine для своего портфолио.

Комплект содержит:

- 416 видеоуроков

- 95 часов видео

- 1024 задания для закрепления материала из уроков

- 3 финальных тестирования

- 4 сертификата

- 12 Бонусных курсов

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Инициализация в C++: разница между =, () и {} с примерами

Инициализация в C++: разница между =, () и {} с примерами

Запрос «инициализация в C++: = () {}» часто встречается у начинающих и продолжающих разработчиков. Разные формы инициализации влияют на то, какие конструкторы вызываются, как проверяются ошибки и даже на то, будет ли объект корректно создан. Ниже — практическое руководство с примерами и советами, которое поможет уверенно выбирать нужный синтаксис.

Что такое инициализация в C++ и почему это важно

Инициализация — это способ задать начальное состояние объекта. От выбранной формы зависят:

  • какой конструктор или правило инициализации будет применено;
  • произойдёт ли проверка сужения (narrowing);
  • не попадём ли мы в ловушки парсинга (например, «most vexing parse»);
  • как будут инициализироваться агрегаты и контейнеры.

Копирующая, прямая и списковая инициализация: =, (), {}

Базовые формы на примере простых типов:

int a = 1;     // copy initialization (копирующая)
int b(1);      // direct initialization (прямая)
int c{1};      // direct list initialization (списковая)
int d = {1};   // copy list initialization (списковая через =)

int z{};       // value/zero initialization: z == 0

Ключевые отличия:

  • = вызывает копирующую инициализацию; не участвуют explicit-конструкторы;
  • () вызывает прямую инициализацию; explicit-конструкторы допускаются;
  • {} включает списковую инициализацию, даёт защиту от сужения и может выбирать перегрузки с std::initializer_list.

Проверка сужения (narrowing) только для {}

Списковая инициализация запрещает неявное сужение типа, что часто спасает от скрытых багов:

int i1 = 3.14; // допустимо: 3.14 будет усечено до 3 (часто лишь предупреждение)
int i2(3.14);  // допустимо, но также приведёт к усечению
int i3{3.14};  // ОШИБКА компиляции: narrowing при {} запрещён

Вывод: для безопасной инициализации чисел предпочитайте {} — компилятор раньше поймает опасные преобразования.

std::initializer_list и выбор перегрузок при {}

Когда у класса есть перегрузка конструктора с std::initializer_list, форма {} обычно выбирает именно её. Это важно для контейнеров и собственных типов.

#include <initializer_list>
#include <iostream>

struct Widget {
    Widget(int a, int b) { std::cout << "(int,int)\n"; }
    Widget(std::initializer_list<int> l) { std::cout << "initializer_list size=" << l.size() << "\n"; }
};

int main() {
    Widget w1(1, 2);   // (int,int)
    Widget w2{1, 2};   // initializer_list
    Widget w3 = {1, 2}; // initializer_list
}

С контейнерами различие особенно заметно:

#include <vector>

std::vector<int> v1(5, 10); // пять элементов, каждый равен 10
std::vector<int> v2{5, 10}; // два элемента: 5 и 10

Совет: если хотите «пять десяток» — используйте (), если «список значений» — {}.

explicit-конструкторы и выбор формы

Ключевое слово explicit запрещает неявные преобразования при копирующей инициализации (=). Прямая и списковая инициализация explicit-конструкторы допускают.

struct X {
    explicit X(int) {}
};

X a = 1;   // ОШИБКА: explicit не допускает copy init
X b(1);    // ОК: direct init
X c{1};    // ОК: direct list init

Most vexing parse и нулевая инициализация

Скобки () могут быть разобраны компилятором как объявление функции, а не объекта. Классический пример:

#include <vector>

std::vector<int> v(); // Объявление функции v, возвращающей vector<int>, а НЕ объект!
std::vector<int> v1{}; // Объект: пустой вектор
int x{};               // x == 0 (value/zero init)

Используйте {} для инициализации по умолчанию и избежания неоднозначностей.

Типы инициализации в терминах стандарта

  • Zero-initialization: обнуление фундаментальных типов при определённых контекстах (например, int x{}; new int{}).
  • Default-initialization: вызывает конструктор по умолчанию (например, T x; внутри функции — без обнуления примитивов).
  • Value-initialization: T x{}; создаёт «значение по умолчанию» (для примитивов — ноль).
  • Copy initialization: T x = expr; не использует explicit-конструкторы.
  • Direct initialization: T x(expr); допускает explicit-конструкторы.
  • List initialization: T x{...}; даёт защиту от narrowing и может выбирать initializer_list.

Агрегаты, {} и назначенные инициализаторы (C++20)

Агрегаты (простые структуры без пользовательских конструкторов) удобно инициализировать через {}:

struct Point { int x; int y; };

Point p1{1, 2};     // aggregate init
Point p2{};         // x=0, y=0

С C++20 доступны назначенные инициализаторы (designated initializers):

Point p3{ .y = 2, .x = 1 }; // порядок произвольный

Поддержка в компиляторах уже широкая, но проверяйте свой стандарт (-std=c++20) и версию компилятора, особенно под Windows.

Практические советы и чек-лист

  • Для чисел и простых типов по умолчанию используйте {} — получите нулевую/безопасную инициализацию и защиту от narrowing.
  • Если нужна конкретная перегрузка с количеством/значениями — выбирайте () или {} осознанно (см. пример с std::vector).
  • Если конструктор explicit — избегайте формы с =; применяйте () или {}.
  • Для агрегатов используйте {} и, при необходимости, назначенные инициализаторы (C++20).
  • Чтобы избежать «most vexing parse», не пишите T obj(); используйте T obj{};
  • Помните: при {} конструктор с std::initializer_list имеет приоритет. Это может неожиданно выбрать «списковую» перегрузку.
  • Для безопасного обнуления динамической памяти используйте new T{}, а не new T().

Мини-практикум

Попробуйте предсказать вывод и поведение, затем проверьте в компиляторе.

#include <iostream>
#include <vector>

struct Demo {
    Demo(int, int) { std::cout << "Demo(int,int)\n"; }
    Demo(std::initializer_list<int>) { std::cout << "Demo(init-list)\n"; }
};

int main() {
    int a{};            // ?
    int b{3.7};         // ? (подсказка: narrowing)
    Demo d1(1, 2);      // ?
    Demo d2{1, 2};      // ?
    std::vector<int> v1(3, 7); // ?
    std::vector<int> v2{3, 7}; // ?
}

Заключение

Форма инициализации в C++ — это не просто стиль, а механика, влияющая на выбор конструктора, безопасность преобразований и понятность кода. Запомните простое правило: для безопасного старта — {}. Для точного выбора перегрузки — осознанно используйте () и {}. Для запрета неявных преобразований — explicit и избегайте =.

Если хотите системно прокачать базу по C++ и закрыть пробелы по инициализации, классам, памяти и стандартной библиотеке, рекомендую посмотреть курс «C++ с Нуля до Гуру: от синтаксиса к реальным проектам». Он практикоориентированный и отлично дополняет материал статьи.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.