<MyRusakov.ru />

Программирование на C++ в Unreal Engine 5

Программирование на C++ в Unreal Engine 5

Данный курс научит Вас созданию игр на C++ в Unreal Engine 5. Курс состоит из 12 разделов, в которых Вас ждёт теория и практика. Причём, в качестве практики будет создан весьма крупный проект объёмом свыше 5000 строк качественного кода, который уже на практике познакомит Вас с принципами создания игр на C++ в Unreal Engine 5.

Параллельно с курсом Вы также будете получать домашние задания, результатом которых станет, в том числе, полноценная серьёзная работа для портфолио.

Помимо самого курса Вас ждёт ещё и очень ценный Бонус: «Тестирование Unreal-проектов на Python», в рамках которого Вы научитесь писать очень полезные тесты для тестирования самых разных аспектов разработки игр.

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

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

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

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

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

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

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

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

Массивы в C++: C‑массивы и std::array — понятное практическое руководство

Массивы в C++: C‑массивы и std::array — понятное практическое руководство

Массивы в C++: C‑массивы vs std::array — практическое руководство для начинающих

Запрос, который часто вводят в поиск: «массивы в C++ std::array для начинающих». В этой статье вы разберётесь, чем отличаются C‑массивы и std::array, как правильно передавать их в функции, как использовать со стандартными алгоритмами и где чаще всего случаются ошибки. В конце — мини‑практикум и рекомендации, что выбрать: C‑массив, std::array или std::vector.

1) Что такое C‑массив и с чего начинается боль

#include <iostream>

int main() {
    int a[5] = {1, 2, 3}; // недостающие элементы обнулятся: {1,2,3,0,0}

    std::cout << a[0] << "\n";   // 1
    std::cout << sizeof(a) << "\n"; // 20 (на тип int по 4 байта) — только здесь, в этой области видимости!
}

Особенность C‑массива: при передаче в функцию он «растворяется» до указателя на первый элемент, и информация о размере теряется. Из‑за этого новички часто ошибаются с sizeof и выходом за границы.

Неправильная передача C‑массива в функцию

#include <iostream>

void print_bad(int arr[]) { // arr == int*; размер неизвестен!
    // Плохо: sizeof(arr) == sizeof(int*), а не размер массива в байтах
    std::cout << "sizeof(arr) = " << sizeof(arr) << "\n";
}

int main() {
    int a[5] = {1,2,3,4,5};
    print_bad(a);
}

Как исправить? Либо передавать размер отдельно, либо — лучше — передавать ссылку на массив известного размера через шаблон.

Правильно: шаблонная ссылка на массив

#include <iostream>

template <std::size_t N>
void print_array(const int (&arr)[N]) {
    for (std::size_t i = 0; i < N; ++i) {
        std::cout << arr[i] << (i + 1 == N ? "\n" : " ");
    }
}

int main() {
    int a[5] = {1,2,3,4,5};
    print_array(a); // N=5 выведен из типа
}

Это безопасно и даёт компилятору знать размер на этапе компиляции. Но работать так с каждым C‑массивом неудобно. Поэтому есть std::array.

2) std::array: фиксированный размер, безопасность и удобство

std::array<T, N> — контейнер фиксированной длины из стандартной библиотеки. Он хранит элементы прямо внутри себя (как C‑массив), но при этом:

  • знает свой размер: .size()
  • работает со стандартными алгоритмами STL
  • имеет методы front, back, fill, data
  • безопаснее: at() проверяет границы и бросает исключение
#include <iostream>
#include <array>

int main() {
    std::array<int, 5> a = {1,2,3,4,5};

    std::cout << a.size() << "\n";  // 5
    std::cout << a.front() << "\n"; // 1
    std::cout << a.back()  << "\n"; // 5

    a[0] = 10;          // без проверки
    // a.at(10) = 42;   // std::out_of_range (если раскомментировать)

    for (int x : a) std::cout << x << ' ';
}

3) Алгоритмы STL со std::array

Алгоритмы работают «из коробки», поскольку std::array предоставляет итераторы.

#include <iostream>
#include <array>
#include <algorithm> // sort, reverse, find

int main() {
    std::array<int, 6> a = {3,1,4,1,5,9};

    std::sort(a.begin(), a.end());
    std::reverse(a.begin(), a.end());

    auto it = std::find(a.begin(), a.end(), 4);
    if (it != a.end()) {
        std::cout << "found at index: " << std::distance(a.begin(), it) << "\n";
    }
}

4) Взаимодействие с C‑API: .data()

Нужно передать «сырой» указатель в функцию C‑библиотеки? У std::array есть .data() — адрес первого элемента.

#include <array>
#include <cstring> // memcpy

int main() {
    std::array<char, 8> buf{};
    const char* src = "hello";
    std::memcpy(buf.data(), src, 6); // включая завершающий \0
}

5) Универсальная передача массивов: std::span (C++20)

std::span<T> — «не владеющий» вид на непрерывную последовательность. Подходит для C‑массивов, std::array и std::vector без копирования и без потери размера.

#include <span>
#include <vector>
#include <array>
#include <iostream>

int sum(std::span<const int> s) {
    int acc = 0;
    for (int x : s) acc += x;
    return acc;
}

int main() {
    int c_arr[3] = {1,2,3};
    std::array<int,3> a = {4,5,6};
    std::vector<int> v = {7,8,9};

    std::cout << sum(c_arr) << "\n"; // 6
    std::cout << sum(a)     << "\n"; // 15
    std::cout << sum(v)     << "\n"; // 24
}

Если у вас C++17 и ниже — можно принимать пару итераторов или указатель+длину, но span заметно упрощает интерфейс.

6) Частые ошибки с массивами

  • Использование sizeof на параметре функции, где массив уже «схлопнулся» до указателя. Решение: std::array, std::span или шаблонная ссылка.
  • Выход за границы (arr[i]>=arr.size()). Для отладки используйте at() у std::array — он бросает исключение.
  • Ожидание «динамической» длины от std::array. Его размер фиксирован во время компиляции. Нужна изменяемая длина — используйте std::vector.
  • Забыли инициализировать. Для C‑массивов используйте список инициализации в фигурных скобках; std::array можно сбросить методом fill.

7) Мини‑практикум: частотность и фильтрация

Посчитаем количество чётных элементов и отфильтруем исходную последовательность в новый буфер. Реализуем на std::span и std::array.

#include <array>
#include <span>
#include <iostream>

std::size_t count_even(std::span<const int> s) {
    std::size_t cnt = 0;
    for (int x : s) if (x % 2 == 0) ++cnt;
    return cnt;
}

// Фильтруем чётные в целевой std::array фиксированного размера
// Возвращаем реальное число записанных элементов
std::size_t filter_even(std::span<const int> in, std::span<int> out) {
    std::size_t w = 0;
    for (int x : in) {
        if (x % 2 == 0) {
            if (w < out.size()) out[w++] = x; // защита от переполнения
        }
    }
    return w;
}

int main() {
    std::array<int, 8> src = {3, 6, 1, 8, 10, 5, 4, 7};
    std::array<int, 8> dst{};

    std::cout << "even count = " << count_even(src) << "\n";

    std::size_t n = filter_even(src, dst);
    for (std::size_t i = 0; i < n; ++i) std::cout << dst[i] << ' '; // 6 8 10 4
}

8) Что выбрать: C‑массив, std::array или std::vector?

  • C‑массив: минимум накладных расходов, хорош для низкоуровневого кода и взаимодействия с C‑API. Требует дисциплины в передаче размера и проверке границ.
  • std::array: фиксированная длина + удобный интерфейс STL. Идеален для небольших статических буферов, константных таблиц, быстрых стековых структур.
  • std::vector: когда размер должен меняться во время выполнения. Если сомневаетесь — начинайте с vector.

9) Советы и лучшие практики

  • Для фиксированного размера в современном C++ почти всегда предпочтителен std::array.
  • Для универсальных API используйте std::span<T> (C++20) вместо пары указатель+длина.
  • При отладке обращений по индексу у std::array используйте at() — поймаете выход за границы раньше.
  • Не злоупотребляйте memcpy; для тривиальных типов ок, но для нетривиальных используйте алгоритмы и копирование элемент‑за‑элементом.

Хотите быстро и системно прокачать основы и практику современного C++ с задачами и обратной связью? Рекомендую посмотреть программу и начать обучение по курсу: Стартовать в C++ с нуля до гуру — пошаговый курс с практикой.

Итог

Если вам нужен фиксированный по размеру массив — выбирайте std::array. Он безопаснее и удобнее C‑массива, дружит с алгоритмами и облегчает написание корректного кода. Для изменяемых по размеру коллекций используйте std::vector. А чтобы делать универсальные функции без копирования — применяйте std::span (C++20).

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

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

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

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

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

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

  1. Кнопка:

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

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

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

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

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

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