Динамические массивы  —  основа многих приложений на C++, это гибкое хранилище, которое расширяется вместе с данными. Изучим принцип работы этих массивов, как они создаются и когда используются в реальных сценариях. Создание простого динамического массива Вот базовая реализация с основными концепциями: template<typename T> class DynamicArray { private:     T* data_;     size_t size_;     size_t capacity_;     void resize(size_t new_capacity) {         T* new_data = new T[new_capacity];         for (size_t i = 0; i < size_; ++i) {             new_data[i] = std::move(data_[i]);         }         delete[] data_;         data_ = new_data;         capacity_ = new_capacity;     } public:     DynamicArray() : data_(new T[2]), size_(0), capacity_(2) {}         ~DynamicArray() {         delete[] data_;     }         void push_back(const T& value) {         if (size_ == capacity_) {             resize(capacity_ * 2);         }         data_[size_++] = value;     }         T& operator[](size_t index) {         if (index >= size_) {             throw std::out_of_range("Index out of bounds");         }         return data_[index];     }         size_t size() const { return size_; }     size_t capacity() const { return capacity_; } }; Реальный пример: логгер событий Вот практическое применение динамического массива: struct LogEntry {     std::string timestamp;     std::string message;     std::string severity;         LogEntry(std::string ts, std::string msg, std::string sev)         : timestamp(std::move(ts)),           message(std::move(msg)),           severity(std::move(sev)) {} }; class EventLogger { private:     DynamicArray<LogEntry> logs;     public:     void log(const std::string& message, const std::string& severity) {         auto now = std::chrono::system_clock::now();         auto time = std::chrono::system_clock::to_time_t(now);         std::string timestamp = std::ctime(&time);         timestamp.pop_back(); // Удаляется символ новой строки                 logs.push_back(LogEntry(timestamp, message, severity));     }         void dump_logs() const {         for (size_t i = 0; i < logs.size(); ++i) {             std::cout << logs[i].timestamp << " ["                      << logs[i].severity << "] "                      << logs[i].message << "\n";         }     } }; Добавление важного функционала Расширим функционал динамического массива: template<typename T> class DynamicArray {     // ... предыдущий код ... public:     // Конструктор копирования     DynamicArray(const DynamicArray& other)         : data_(new T[other.capacity_]),           size_(other.size_),           capacity_(other.capacity_) {         for (size_t i = 0; i < size_; ++i) {             data_[i] = other.data_[i];         }     }         // Конструктор перемещения     DynamicArray(DynamicArray&& other) noexcept         : data_(other.data_),           size_(other.size_),           capacity_(other.capacity_) {         other.data_ = nullptr;         other.size_ = other.capacity_ = 0;     }         // Оператор присваивания     DynamicArray& operator=(const DynamicArray& other) {         if (this != &other) {             delete[] data_;             data_ = new T[other.capacity_];             size_ = other.size_;             capacity_ = other.capacity_;             for (size_t i = 0; i < size_; ++i) {                 data_[i] = other.data_[i];             }         }         return *this;     }         void pop_back() {         if (size_ > 0) {             --size_;         }     }         void clear() {         size_ = 0;     }         bool empty() const {         return size_ == 0;     }         T& front() {         if (empty()) {             throw std::out_of_range("Array is empty");         }         return data_[0];     }         T& back() {         if (empty()) {             throw std::out_of_range("Array is empty");         }         return data_[size_ - 1];     } }; Динамические массивы в очереди задач Вот практический пример использования динамических массивов в системе планирования задач: class Task { public:     std::function<void()> function;     int priority;     std::string name;         Task(std::function<void()> f, int p, std::string n)         : function(std::move(f)), priority(p), name(std::move(n)) {} }; class TaskQueue { private:     DynamicArray<Task> tasks;     public:     void add_task(std::function<void()> func, int priority,                   const std::string& name) {         tasks.push_back(Task(std::move(func), priority, name));                 // Выполняется сортировка по приоритету в порядке убывания         for (size_t i = tasks.size() - 1; i > 0; --i) {             if (tasks[i].priority > tasks[i-1].priority) {                 std::swap(tasks[i], tasks[i-1]);             } else {                 break;             }         }     }         void execute_all() {         while (!tasks.empty()) {             tasks.front().function();             tasks.pop_back();         }     }         void show_queue() const {         for (size_t i = 0; i < tasks.size(); ++i) {             std::cout << "Task: " << tasks[i].name                      << " (Priority: " << tasks[i].priority << ")\n";         }     } }; Управление памятью и производительность Вот как оптимизируется производительность динамического массива: template<typename T> class DynamicArray {     // ... предыдущий код ... public:     void reserve(size_t new_capacity) {         if (new_capacity > capacity_) {             resize(new_capacity);         }     }         void shrink_to_fit() {         if (capacity_ > size_) {             resize(size_);         }     }         // Эффективная вставка в любой позиции     void insert(size_t index, const T& value) {         if (index > size_) {             throw std::out_of_range("Invalid insertion index");         }                 if (size_ == capacity_) {             resize(capacity_ * 2);         }                 for (size_t i = size_; i > index; --i) {             data_[i] = std::move(data_[i-1]);         }                 data_[index] = value;         ++size_;     }         // Эффективное удаление в любой позиции     void erase(size_t index) {         if (index >= size_) {             throw std::out_of_range("Invalid erasure index");         }                 for (size_t i = index; i < size_ - 1; ++i) {             data_[i] = std::move(data_[i+1]);         }                 --size_;     } }; Реальное применение: буфер обработки изображений Вот как динамические массивы используются при обработке изображений: struct Pixel {     uint8_t r, g, b;         Pixel(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0)         : r(r), g(g), b(b) {} }; class ImageBuffer { private:     DynamicArray<Pixel> pixels;     size_t width_;     size_t height_;     public:     ImageBuffer(size_t width, size_t height)         : width_(width), height_(height) {         pixels.reserve(width * height);         for (size_t i = 0; i < width * height; ++i) {             pixels.push_back(Pixel());         }     }         void set_pixel(size_t x, size_t y, const Pixel& p) {         if (x >= width_ || y >= height_) {             throw std::out_of_range("Pixel coordinates out of bounds");         }         pixels[y * width_ + x] = p;     }         Pixel& get_pixel(size_t x, size_t y) {         if (x >= width_ || y >= height_) {             throw std::out_of_range("Pixel coordinates out of bounds");         }         return pixels[y * width_ + x];     }         void apply_grayscale() {         for (size_t i = 0; i < pixels.size(); ++i) {             uint8_t gray = static_cast<uint8_t>(                 (pixels[i].r + pixels[i].g + pixels[i].b) / 3);             pixels[i].r = pixels[i].g = pixels[i].b = gray;         }     } }; Этими реализациями демонстрируется, что динамические массивы  —  это основа многих реальных приложений. Не забывайте бережно относиться к памяти и при выборе между пользовательским динамическим массивом и std::vector учитывать конкретный сценарий. Хотя vector стандартной библиотеки хорошо протестирован и оптимизирован для большинства случаев, благодаря пониманию принципов работы динамических массивов принимаются более взвешенные решения относительно того, когда использовать каждый из вариантов. Читайте также: Как проходится ассоциативный массив на C++ C++: полное руководство по циклам while Механика разрешения имен и связывания на C++ Читайте нас в Telegram, VK и Дзен Перевод статьи ryan: Dynamic Arrays in C++: Comprehensive Guide
==============
Динамические массивы — это гибкое хранилище, которое автоматически увеличивается вместе с данными. Они создаются и используются для хранения изменяемого количества элементов. В примере показано создание и использование динамического массива, а также его применение для логирования событий, где создается структура `LogEntry` и класс `EventLogger` для записи и отображения логов. Также представлены расширенные возможности динамического массива, такие как конструкторы копирования и перемещения, операторы присваивания, а также функции для вставки, удаления и управления памятью, что позволяет эффективно управлять очередью задач. В примере использования динамических массивов для обработки изображений, класс `ImageBuffer` демонстрирует эффективное хранение и манипулирование пикселями, включая операции, такие как изменение цвета на оттенки серого.