maestro7it_education
6️⃣ Указатели и работа с памятью
Указатели в C++ — это переменные, которые хранят адреса других переменных.
Они позволяют вам управлять памятью более гибко и эффективно.
Понимание указателей и работы с памятью критично для написания производительных и безопасных программ.
1. Основы указателей
Объявление и инициализация указателя
Указатель объявляется с использованием оператора *, инициализируется адресом переменной с помощью оператора &.
#include <iostream>
int main() { int value = 10; int *ptr = &value; // Объявление указателя и инициализация адресом переменной value
std::cout << "Значение переменной: " << value << std::endl; std::cout << "Адрес переменной: " << &value << std::endl; std::cout << "Значение указателя: " << ptr << std::endl; std::cout << "Значение, на которое указывает указатель: " << *ptr << std::endl;
return 0;}
Операция разыменования указателя
Операция разыменования указывает на значение, хранящееся по адресу, на который указывает указатель. Используется оператор *
.
#include <iostream>
int main() { int value = 10; int *ptr = &value;
*ptr = 20; // Изменение значения переменной через указатель
std::cout << "Новое значение переменной: " << value << std::endl;
return 0;}
2. Динамическое выделение памяти
Для работы с динамической памятью используются операторы new
и delete
.
Они позволяют выделять и освобождать память во время выполнения программы.
Выделение памяти с помощью new
Оператор new выделяет память на куче и возвращает указатель на неё.
#include <iostream>
int main() { int *ptr = new int; // Выделение памяти для одного целого числа *ptr = 30;
std::cout << "Значение: " << *ptr << std::endl;
delete ptr; // Освобождение памяти
return 0;}
Выделение массива с помощью new
Оператор new[]
выделяет память для массива.
#include <iostream>
int main() { int size = 5; int *arr = new int[size]; // Выделение памяти для массива целых чисел
for (int i = 0; i < size; ++i) { arr[i] = i * 10; }
for (int i = 0; i < size; ++i) { std::cout << "arr[" << i << "] = " << arr[i] << std::endl; }
delete[] arr; // Освобождение памяти для массива
return 0;}
Освобождение памяти с помощью delete
Оператор delete освобождает ранее выделенную память.
#include <iostream>
int main() { int *ptr = new int(40); // Выделение памяти и инициализация std::cout << "Значение: " << *ptr << std::endl; delete ptr; // Освобождение памяти
return 0;}
3. Указатели и массивы
Массивы и указатели тесно связаны в C++.
Имя массива является указателем на первый элемент массива.
#include <iostream>
int main() { int arr[] = {1, 2, 3, 4, 5}; int *ptr = arr; // Указатель на первый элемент массива
for (int i = 0; i < 5; ++i) { std::cout << "arr[" << i << "] = " << *(ptr + i) << std::endl; }
return 0;}
4. Умные указатели (C++11 и позже)
В C++11 введены умные указатели, которые управляют временем жизни объектов и помогают избежать утечек памяти.
Самые популярные умные указатели — это std::unique_ptr
, std::shared_ptr
и std::weak_ptr
.
std::unique_ptr
std::unique_ptr
обеспечивает владение объектом с единственным указателем.
При уничтожении std::unique_ptr
автоматически освобождает память.
#include <iostream>#include <memory> // Для std::unique_ptr
int main() { std::unique_ptr<int> ptr = std::make_unique<int>(50); // Выделение и инициализация памяти std::cout << "Значение: " << *ptr << std::endl; // Память освобождается автоматически при выходе из области видимости
return 0;}
std::shared_ptr
std::shared_ptr
позволяет нескольким указателям разделять владение одним объектом.
Память освобождается, когда последний std::shared_ptr
, владеющий объектом, выходит из области видимости.
#include <iostream>#include <memory> // Для std::shared_ptr
int main() { std::shared_ptr<int> ptr1 = std::make_shared<int>(60); std::shared_ptr<int> ptr2 = ptr1; // Совместное владение
std::cout << "Значение через ptr1: " << *ptr1 << std::endl; std::cout << "Значение через ptr2: " << *ptr2 << std::endl;
// Память освободится после выхода из области видимости последнего shared_ptr
return 0;}
std::weak_ptr
std::weak_ptr
используется вместе с std::shared_ptr
для наблюдения за объектом без увеличения счётчика ссылок, что помогает избежать циклических ссылок.
#include <iostream>#include <memory> // Для std::weak_ptr и std::shared_ptr
int main() { std::shared_ptr<int> sharedPtr = std::make_shared<int>(70); std::weak_ptr<int> weakPtr = sharedPtr; // Наблюдатель
if (auto lockedPtr = weakPtr.lock()) { // Проверка, что объект всё ещё существует std::cout << "Значение через weak_ptr: " << *lockedPtr << std::endl; } else { std::cout << "Объект уже удалён." << std::endl; }
return 0;}
Указатели и работа с памятью — это важные концепции в C++, которые позволяют более гибко управлять ресурсами и оптимизировать производительность.
Однако неправильное использование указателей может привести к утечкам памяти и другим проблемам.
Умные указатели, введенные в C++11, упрощают управление памятью и помогают избежать распространённых ошибок.
Автор: Дуплей Максим Игоревич
Дата: 07.09.2024
Версия 1.0