- Updated summarization prompt to require Russian output and exclude non-textual elements - Upgraded ollama dependency to v0.6.1 - Enhanced run.sh script to support both single record and file-based ID input for MongoDB test generation - Updated documentation in scripts/README.md to reflect new functionality - Added verbose flag to generate_summarization_from_mongo.py for better debugging ``` This commit message follows the conventional commit format with a short title (50-72 characters) and provides a clear description of the changes made and their purpose.
3 lines
9.7 KiB
Plaintext
3 lines
9.7 KiB
Plaintext
Динамические массивы — основа многих приложений на 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
|
||
==============
|