Created by drewxa@
Низкоуровневые языки программирования требуют ручного управления оперативной памятью.
Необходимо корректно выделять и освобождать.
char* array = nullptr;
size_t sz = 1 * 1024 /*kb*/ *
1024 /*Mb*/ *
1024 /*Gb*/;
for (int i = 0; i < 5; ++i) {
array = new char[sz];
// использование array
// и утечка памяти...
}
delete[] array;
Неправильное освобождение памяти
Unit* warrior = new Knight();
Unit* ptr = warrior;
// использование указателей
delete warrior;
delete ptr;
Повторное освобождение памяти
Resource Acquisition Is Initialization - идиома объектно-ориентированного программирования, смысл которой заключается в том, что получение некоторого ресурса неразрывно совмещается с инициализацией объекта, а освобождение — с уничтожением.
Другими словами, выделяем память (или любой другой ресурс) в конструкторе некого объекта, а освобождаем - в деструкторе.
template <class T>
struct ScopedPtr {
T* ptr_;
ScopedPtr(T* ptr) {
ptr_ = ptr;
}
~ScopedPtr() {
delete ptr_;
}
};
ScopedPtr<Unit> guard(new Knight);
boost::scoped_ptr
std::unique_ptr
std::shared_ptr
std::weak_ptr
std::auto_ptr
boost::scoped_ptr
Пожалуй, самый простой среди “умных” указателей.
Является некопируемым и неперемещаемым объектом.
boost::scoped_ptr
Благодаря scoped_ptr
разработчику не требуется вызывать delete.
// При разрушении объекта |guard| вызовется деструктор
// класса boost::scoped_ptr, в котором
// и вызовется delete для класска Image.
auto* ptr = new Image("~/photo1.png");
boost::scoped_ptr<Image> guard(ptr);
// Нет явного вызова delete для |ptr|.
std::unique_ptr
std::unique_ptr
- владеет объектом, на который указывает, т.е. отвечает за уничтожение объекта и освобождение памяти.
std::unique_ptr
- является некопируемый, но перемещаемым объектом.
Его нельзя копировать!
Но можно перемещать.
При попытке копировать std::unique_ptr
получим ошибку компиляции.
std::unique_ptr ptr(new Image("~/photo.png"));
// Вызов конструктора копирования.
std::unique_ptr another_ptr = ptr;
In function 'int main()':
10:36: error: use of deleted function 'std::unique_ptr<_Tp,
_Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&)
[with _Tp = int; _Dp = std::default_delete<int>]'
In file included from /usr/include/c++/4.9/memory:81:0, from 4:
/usr/include/c++/4.9/bits/unique_ptr.h:356:7: note declared here
unique_ptr(const unique_ptr&) = delete;
Но std::unique_ptr
можно перемещать.
std::unique_ptr ptr(new Image("~/photo.png"));
// Вызов конструктора перемещения.
std::unique_ptr another_ptr = std::move(ptr);
// |ptr| никуда не указывает.
assert(ptr == nullptr);
// |another_ptr| владеет объектом Image.
assert(another_ptr != nullptr);
по умолчанию, std::unique_ptr
имеет тот же размер, что и обычные указатели
для большинства операций выполняются точно такие же команды
значит, что std::unique_ptr
можно использовать, когда важны расход памяти и времени
std::vector<std::unique_ptr> array;
array.push_back(new Image("~/photo.png"));
// А при использовании boost::scoped_ptr
// возникнет ошибка компиляции.
std::vector<boost::scoped_ptr> array;
array.push_back(new Image("~/photo.png"));
по умолчанию, std::unique_ptr
освобождает ресурс через оперетор delete
но данное поведение можно настроить
при создании std::unique_ptr
можно указать произвольную функцию, которая будет вызываться для освобождения ресурса вместо delete
std::shared_ptr
Указатель std::shared_ptr
используется для управления ресурсами путем совместноrо владения, т.е. объект, на который указывает shared_ptr
, уничтожится только после того, как не останется ни одного shared_ptr
, ссылающегося на него.
std::shared_ptr ptr(new Image("~/photo.png"));
// Copy:
std::shared_ptr another_ptr = ptr;
assert(ptr != nullptr);
assert(another_ptr != nullptr);
// Move:
std::shared_ptr yet_another_ptr = std::move(ptr);
assert(ptr == nullptr);
assert(yet_another_ptr != nullptr);
assert(another_ptr != nullptr);
Подсчет ссылок в shared_ptr
построен с использованием атомарного счетчика. Можно безопасно использовать указатели на один и тот же объект из разных потоков. Во всяком случае, не стоит беспокоиться о подсчете ссылок. Потокобезопасность самого объекта – другая проблема, и о ней надо заботится отдельно.
std::shared_ptr
Двойное освобождение памяти
Image* raw = new Image("~/photo.png");
std::unique_ptr ptr = std::unique_ptr(raw);
std::unique_ptr yet_ptr = std::unique_ptr(raw);
… тоже самое и с shared_ptr
Image* raw = new Image("~/photo.png");
std::shared_ptr ptr = std::shared_ptr(raw);
std::shared_ptr yet_ptr = std::shared_ptr(raw);
// Creating unique:
std::unique_ptr ptr =
std::make_unique<Image>("~/photo.png");
// Creating shared:
std::shared_ptr another_ptr =
std::make_shared<Image>("~/photo.png");
если вам достаточно исключительного владения, лучшим выбором является std::unique_ptr
его производительность близка к производительности обычных указателей, а преобразование в std::shared_ptr
выполняется очень
в большинстве случаев применение std::shared_ptr
предпочтительнее, чем ручное управление временем жизни объекта
std::weak_ptr
std::unique_ptr