Интеллектуальный указатель - это объект класса, который действует подобно указателю, но обладает дополнительными возможностями.
В предыдущем стандарте C++03 в наличии имелось только два вида указателей, стандартный и один умный std::auto_ptr.
Проблема std::auto_ptr, выявляется в коде ниже:
1 2 3 | auto_ptr<string> p1(new string("Hello")); auto_ptr<string> p2; p2 = p1; |
В строке 3 p2 получает права владения объектом string, указатель p1 лишается этих прав. Это вроде бы хорошо так как вызывается один раз деструктор для указателя, а не два раза чтобы удалить один и тот же объект. Но вдруг программа где то использует данные из p1. А p1 уже не указывает на данные.
Пример с контейнером:
Элемент массива становится не валидным, так как в 16 строке мы передали права на объект указателю pFilm. Программа скомпилируется но выдаст ошибку в процессе выполнения.
std::unique_ptr - немного отличается от std::auto_ptr, тем что запрещает копирование. Это безопаснее так как мы увидим ошибку на этапе компиляции, а не увидим сбой программы и будем искать ошибку.
Пример с контейнером:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <iostream> #include <string> #include <memory> int main() { using namespace std; auto_ptr<string> films[5] = { auto_ptr<string> (new string("Hello")), auto_ptr<string> (new string("Goodbuy")), auto_ptr<string> (new string("Good morning")), auto_ptr<string> (new string("Good evening")), auto_ptr<string> (new string("Good afternoon")) }; auto_ptr<string> pFilm; pFilm = films[3]; for(int i(0); i < 5; ++i) { cout << *films[i] << endl; } } |
Элемент массива становится не валидным, так как в 16 строке мы передали права на объект указателю pFilm. Программа скомпилируется но выдаст ошибку в процессе выполнения.
***
Для изменения прав на объект используется std::move
1 2 3 | unique_ptr<string> p1(new string("Hello")); unique_ptr<string> p2; p2 = std::move(p1); |
Как для std::auto_ptr так и для shared_ptr есть методы для сброса прав указателя reset(), для возвращения классического указателя используется метод get().
Подробнее:
std::unique_ptr – умный указатель, который: получает единоличное владение объектом через его указатель, и разрушает объект через его указатель, когда unique_ptr выходит из области видимости.
unique_ptr не может быть скопирован или задан через операцию присвоения, два экземпляра unique_ptr не могут управлять одним и тем же объектом. Неконстантный unique_ptr может передать владение управляемым объектом другому указателю unique_ptr. const std::unique_ptr не может быть передан, ограничивая время жизни управляемого объекта областью, в которой указатель был создан. Когда unique_ptr уничтожается, он удаляет объект с помощью Deleter.
Существует две версии std::unique_ptr:
1) управляет временем жизни одного объекта, например, созданного с помощью оператора new
2) управляет временем жизни массива, с длиной, определенной во время выполнения, созданного с помощью new[]
Типичные случаи применения std::unique_ptr включают:
обеспечение безопасности исключений для классов и функций, которые управляют объектами с динамическим временем жизни, гарантируя удаление в случае нормального завершения и завершения по исключению передача владения динамически созданным объектом в функции
получение владения динамически созданным объектом из функций в качестве типа элемента в контейнерах, поддерживающих семантику перемещения, таких как std::vector, которые хранят указатели на динамически выделенные объекты (например, если желательно полиморфное поведение)
Ссылка: http://ru.cppreference.com/w/cpp/memory/unique_ptr
Для просмотра количества ссылающихся указателей используется функция: std::shared_ptr.use_count()
Для создания объектов на лету следует использовать фабричную функцию std::make_shared<T>. Создает объект типа T и оборачивает его в std::shared_ptr использованием args как список параметров для конструктора T.
Что произойдет при выходе объектов a и b из области определения? В деструкторе уменьшатся ссылки на объекты. У каждого объекта будет счетчик = 1 (ведь a все еще указывает на b, а b — на a). Объекты “держат” друг друга и у нашего приложения нет возможности получить к ним доступ — эти объекты “потеряны”.
Для решения этой проблемы существует weak_ptr. Одним из типичных случаев создания перекрестных ссылок является случай, когда один объект владеет коллекцией других объектов.
Заменяем указатель на std::weak_ptr и проблема решена.
Подробнее:
std::unique_ptr – умный указатель, который: получает единоличное владение объектом через его указатель, и разрушает объект через его указатель, когда unique_ptr выходит из области видимости.
unique_ptr не может быть скопирован или задан через операцию присвоения, два экземпляра unique_ptr не могут управлять одним и тем же объектом. Неконстантный unique_ptr может передать владение управляемым объектом другому указателю unique_ptr. const std::unique_ptr не может быть передан, ограничивая время жизни управляемого объекта областью, в которой указатель был создан. Когда unique_ptr уничтожается, он удаляет объект с помощью Deleter.
Существует две версии std::unique_ptr:
1) управляет временем жизни одного объекта, например, созданного с помощью оператора new
2) управляет временем жизни массива, с длиной, определенной во время выполнения, созданного с помощью new[]
Типичные случаи применения std::unique_ptr включают:
обеспечение безопасности исключений для классов и функций, которые управляют объектами с динамическим временем жизни, гарантируя удаление в случае нормального завершения и завершения по исключению передача владения динамически созданным объектом в функции
получение владения динамически созданным объектом из функций в качестве типа элемента в контейнерах, поддерживающих семантику перемещения, таких как std::vector, которые хранят указатели на динамически выделенные объекты (например, если желательно полиморфное поведение)
Ссылка: http://ru.cppreference.com/w/cpp/memory/unique_ptr
***
std::shared_ptr - самый часто используемый интеллектуальный указатель. Несколько указателей данного класса могут ссылаться на один объект. std::shared_ptr - ведёт подсчёт ссылок на используемый ресурс. Ресурс освободится когда количество ссылок указателя будет равно 0.Для просмотра количества ссылающихся указателей используется функция: std::shared_ptr.use_count()
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <iostream> #include <memory> using namespace std; int main(int argc, char *argv[]) { shared_ptr<int> ptr1(new int(66)); shared_ptr<int> empty_ptr; empty_ptr = ptr1; cout << empty_ptr.use_count(); // Выведет 2; return 0; } |
Для создания объектов на лету следует использовать фабричную функцию std::make_shared<T>. Создает объект типа T и оборачивает его в std::shared_ptr использованием args как список параметров для конструктора T.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <iostream> #include <memory> void foo(std::shared_ptr<int> i) { (*i)++; } int main() { auto sp = std::make_shared<int>(10); foo(sp); std::cout << *sp << std::endl; } |
***
std::weak_ptr – умный указатель, который содержит "слабую" ссылку на объект, управляемый указателем std::shared_ptr. Он должен быть преобразован в std::shared_ptr, чтобы получить доступ к управляемому объекту.
Данный указатель позволяет решить проблему перекрёстных ссылок:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <iostream> #include <memory> using namespace std; struct Foo { shared_ptr<Foo> otherFoo; }; void f() { shared_ptr<Foo> a(new Foo); shared_ptr<Foo> b(new Foo); a->otherFoo = b; b->otherFoo = a; cout << a.use_count() << " : " << b.use_count(); 2 : 2 } int main() { f(); return 0; } |
Для решения этой проблемы существует weak_ptr. Одним из типичных случаев создания перекрестных ссылок является случай, когда один объект владеет коллекцией других объектов.
Заменяем указатель на std::weak_ptr и проблема решена.
1 2 3 4 | struct Foo { weak_ptr<Foo> otherFoo; }; |
0 коммент.:
Отправить комментарий