Storage duration – это свойство объекта, которое описывает, когда тот попадает в память и когда её освобождает. В C++ их 4 вида:
- автоматическая storage duration (на основании scope)
- статическая (static, extern)
- storage duration потока
- динамическая (new/delete)
Проблемы:
- утечка памяти (не вызывается delete)
- сложность разделения указателей не владеющие объектом (owning pointer) и использующие объект (non owning pointer)
- при использовании простых указателей (raw pointer) сложно без комментариев определить какой тип указателя (owning/non owning pointer)
Где должен вызываться delete?
int* func();
Класс, который ссылается на объект в динамической памяти и при выходе из области видимости уничтожает хранимый объект.
{
std::unique_ptr<X> prt(new X());
} // здесь указатель уничтожается, перед этим память под X освобождается
Проблемы:
- нужно писать имя класса дважды:
- есть проблема неопределенного порядка вычисления аргументов
void func(std::unique_ptr<A> a,std::unique_ptr<B> b){};
int main(){
func(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B()));
}
Возможен следующий порядок вычисления аргументов:
new A()
new B()
std::unique_prt<A>( ... )
std::unique_prt<B>( ... )
std::make_unique решает эти проблемы
auto prt = std::make_unique<X>();
Особенности:
- std::unique_ptr - объект должен иметь только одного владельца
- право на владение можно передать std::move()
void func(std::unique_prt<X> a){}
int main(){
auto a = std::make_unique<X>();
func(a); // не скомпилируется
func(std::move(a)); // владение передано в func, при выходе из func объект будет освобожден
}
- std::unique_ptr нельзя копировать
- объект для использования можно передавать по raw pointer
void func(X* a){}
int main(){
auto a = std::make_unique<X>();
finc(a.get());
}
std::shared_ptr - класс, который ссылается на объект в динамической памяти, у которого может быть несколько владельцев, и при уничтожении всех владельцев класс уничтожает хранимый объект.
{
auto prt = std::make_shared<X>();
{
auto ptr2 = ptr;
}
}
std::weak_ptr - это фактически умный указатель non owning, предназначенный для использования именно с std::shared_ptr
Особенности:
- Копирование std::weak_ptr не увеличивает счётчик в std::shared_ptr, а значит и не защищает объект от уничтожения
- всегда имеется возможность проверить, существует ли ещё объект, на который ссылается std::weak_ptr, или нет
Вообще говоря, std::weak_ptr необходимо использовать всегда, когда надо ссылаться на управляемый std::shared_ptr объект, но не защищать его от уничтожения.
Не использовать. Этот умный указатель был помечен как устаревший в C++ 11, а в C++ 17 был полностью удалён из стандарта языка
Причины:
- std::auto_ptr реализовывает семантику перемещения через конструктор копирования и оператор присваивания. Объект удаляется при передачи в функцию по значению
- std::auto_ptr всегда удаляет свое содержимое, используя оператор delete, который не работает с массивами