Умный указатель - Smart pointer
Эта статья нужны дополнительные цитаты для проверка.Июнь 2015 г.) (Узнайте, как и когда удалить этот шаблон сообщения) ( |
В Информатика, а умный указатель является абстрактный тип данных который имитирует указатель предоставляя дополнительные функции, такие как автоматический управление памятью или же проверка границ. Такие функции предназначены для уменьшения количества ошибок, вызванных неправильным использованием указателей, при сохранении эффективности. Интеллектуальные указатели обычно отслеживают память, на которую они указывают, и также могут использоваться для управления другими ресурсами, такими как сетевые соединения и дескрипторы файлов. Умные указатели были впервые популяризированы в языке программирования C ++ в первой половине 1990-х годов как опровержение критики отсутствия в C ++ автоматический сбор мусора.[1][2]
Неправильное использование указателя может быть основным источником ошибок. Умные указатели предотвращают большинство ситуаций утечки памяти сделав освобождение памяти автоматическим. В более общем плане они делают разрушение объекта автоматически: объект, управляемый умным указателем, автоматически уничтожается (завершено а затем освобождается), когда последний (или единственный) владелец объекта уничтожается, например, потому что владельцем является локальная переменная, и выполнение оставляет переменную объем. Умные указатели также устраняют висячие указатели откладывая уничтожение до тех пор, пока объект не перестанет использоваться.
Если язык поддерживает автоматическую сборку мусора (например, Ява или же C # ), то интеллектуальные указатели не нужны для восстановления и безопасности управления памятью, но полезны для других целей, таких как тайник структура данных управления резиденцией и Управление ресурсами таких объектов, как файловые ручки или же сетевые розетки.
Существует несколько типов интеллектуальных указателей. Некоторые работают с подсчет ссылок, другие путем присвоения права собственности на объект одному указателю.
История
Несмотря на то, что C ++ популяризировал концепцию интеллектуальных указателей, особенно подсчитанный по ссылкам Разнообразие, непосредственный предшественник одного из языков, вдохновивших разработку C ++, имел ссылки с подсчетом ссылок, встроенные в язык. C ++ частично был вдохновлен Simula67.[3] Предком Simula67 был Simula I. Поскольку Simula I. элемент аналогичен указателю C ++ без ноль, и поскольку процесс Simula I с фиктивным оператором в качестве тела его действия аналогичен C ++ структура (что само по себе аналогично работе C.A.R. Hoare's записывать в тогдашних работах 1960-х годов) в Simula I были элементы с подсчетом ссылок (то есть выражения-указатели, которые содержат косвенное обращение) к процессам (то есть записям) не позднее сентября 1965 года, как показано в приведенных ниже абзацах.[4]
На процессы можно ссылаться индивидуально. Физически ссылка на процесс - это указатель на область памяти, содержащую локальные для процесса данные и некоторую дополнительную информацию, определяющую его текущее состояние выполнения. Однако по причинам, указанным в разделе 2.2, ссылки на процессы всегда косвенные, через элементы, называемые элементы. Формально ссылка на процесс - это значение выражения типа элемент.
…
элемент значения могут быть сохранены и извлечены путем присвоений и ссылок на элемент переменные и другими способами.
Язык содержит механизм, позволяющий сделать атрибуты процесса доступными извне, то есть изнутри других процессов. Это называется удаленным доступом. Таким образом, процесс - это ссылочная структура данных.Стоит отметить сходство между процессом, тело активности которого является фиктивным оператором, и концепцией записи, недавно предложенной К. А. Р. Хоаром и Н. Виртом.
Поскольку C ++ заимствовал Симула подход к распределению памяти - новый ключевое слово при выделении процесса / записи для получения свежего элемент к этому процессу / записи - неудивительно, что C ++ в конечном итоге воскресил в Simula механизм интеллектуальных указателей с подсчетом ссылок в элемент также.
Функции
В C ++, интеллектуальный указатель реализован как шаблонный класс, который имитирует, посредством перегрузка оператора, поведение традиционного (необработанный) указатель, (например, разыменование, присвоение) с предоставлением дополнительных функций управления памятью.
Умные указатели могут облегчить преднамеренное программирование выражая в типе способ управления памятью референта указателя. Например, если функция C ++ возвращает указатель, нет способа узнать, должен ли вызывающий объект удалить память референта, когда вызывающий закончит с информацией.
SomeType* Неоднозначный(); // Что делать с результатом?
Традиционно для разрешения неоднозначности использовались соглашения об именах,[5] который подвержен ошибкам и является трудоемким. C ++ 11 представил способ гарантировать правильное управление памятью в этом случае, объявив функцию, возвращающую unique_ptr
,
стандартное::unique_ptr<SomeType> ObviousFunction();
Объявление типа возвращаемого значения функции как unique_ptr
делает явным тот факт, что вызывающий объект становится владельцем результата, а среда выполнения C ++ гарантирует, что память будет освобождена автоматически. Перед C ++ 11, unique_ptr можно заменить на auto_ptr.
Создание новых объектов
Чтобы облегчить выделение
стандартное::shared_ptr<SomeType>
C ++ 11 введено:
авто s = стандартное::make_shared<SomeType>(конструктор, параметры, Вот);
и аналогично
стандартное::unique_ptr<some_type>
С C ++ 14 можно использовать:
авто ты = стандартное::make_unique<SomeType>(конструктор, параметры, Вот);
Практически во всех обстоятельствах предпочтительно использовать эти средства, а не новый
ключевое слово:[6]
unique_ptr
C ++ 11 вводит std :: unique_ptr
, определенный в заголовке <memory>
.[7]
А unique_ptr
это контейнер для необработанного указателя, который unique_ptr
говорят, что владеет. А unique_ptr
явно предотвращает копирование содержащегося в нем указателя (как это произошло бы при обычном назначении), но std :: move
функция может использоваться для передачи владения содержащимся указателем другому unique_ptr
. А unique_ptr
не может быть скопирован, потому что его конструктор копирования и операторы присваивания явно удалены.
стандартное::unique_ptr<int> p1(новый int(5));стандартное::unique_ptr<int> p2 = p1; // Ошибка компиляции.стандартное::unique_ptr<int> p3 = стандартное::двигаться(p1); // Передает право собственности. p3 теперь владеет памятью, а p1 имеет значение nullptr.p3.перезагрузить(); // Удаляет память.p1.перезагрузить(); // Ничего не делает.
std ::auto_ptr
является устарел под C ++ 11 и полностью удален из C ++ 17. Конструктор копирования и операторы присваивания auto_ptr
фактически не копируйте сохраненный указатель. Вместо этого они передать это, оставив предыдущий auto_ptr
объект пустой. Это был один из способов реализовать строгое владение, так что только один auto_ptr
объект может владеть указателем в любой момент времени. Это означает, что auto_ptr
не следует использовать там, где требуется семантика копирования.[8][нужна цитата ] С auto_ptr
уже существовал с его семантикой копирования, его нельзя было обновить до указателя только для перемещения без нарушения Обратная совместимость с существующим кодом.
C ++ 11 представляет std :: shared_ptr
и std :: weak_ptr
, определенный в заголовке <memory>
.[7] C ++ 11 также вводит std :: make_shared
(std :: make_unique
был введен в C ++ 14) для безопасного выделения динамической памяти в RAII парадигма.[9]
А shared_ptr
контейнер для необработанный указатель. Он поддерживает подсчет ссылок владение содержащимся в нем указателем вместе со всеми копиями shared_ptr
. Объект, на который ссылается содержащийся необработанный указатель, будет уничтожен тогда и только тогда, когда все копии shared_ptr
были уничтожены.
стандартное::shared_ptr<int> p0(новый int(5)); // Допустимо, выделяет 1 целое число и инициализирует его значением 5.стандартное::shared_ptr<int[]> p1(новый int[5]); // Допустимо, выделяет 5 целых чисел.стандартное::shared_ptr<int[]> p2 = p1; // Теперь память принадлежит обоим.p1.перезагрузить(); // Память все еще существует из-за p2.p2.перезагрузить(); // Освобождает память, так как никто другой не владеет памятью.
А weak_ptr
это контейнер для необработанного указателя. Он создан как копия shared_ptr
. Существование или уничтожение weak_ptr
копии shared_ptr
не влияют на shared_ptr
или другие его копии. Ведь копии shared_ptr
были уничтожены, все weak_ptr
копии становятся пустыми.
стандартное::shared_ptr<int> p1 = стандартное::make_shared<int>(5);стандартное::weak_ptr<int> wp1 {p1}; // p1 владеет памятью.{ стандартное::shared_ptr<int> p2 = wp1.замок(); // Теперь p1 и p2 владеют памятью. // p2 инициализируется слабым указателем, поэтому вам нужно проверить, // память все еще существует! если (p2) { DoSomethingWith(p2); }}// p2 уничтожен. Память принадлежит p1.p1.перезагрузить(); // Освободить память.стандартное::shared_ptr<int> p3 = wp1.замок(); // Памяти больше нет, поэтому мы получаем пустой shared_ptr.если (p3) { // код не будет выполняться ActionThatNeedsALivePointer(p3);}
Поскольку реализация shared_ptr
использует подсчет ссылок, циркулярные ссылки потенциально проблема. Циркуляр shared_ptr
цепочку можно разорвать, изменив код так, чтобы одна из ссылок была weak_ptr
.
Несколько потоков могут безопасно одновременно обращаться к разным shared_ptr
и weak_ptr
объекты, указывающие на один и тот же объект.[10]
Указанный объект должен быть защищен отдельно, чтобы гарантировать безопасность потоков.
shared_ptr
и weak_ptr
основаны на версиях, используемых Библиотеки Boost.[нужна цитата ] Технический отчет C ++ 1 (TR1) впервые представил их в стандарте, так как общие коммунальные услуги, но C ++ 11 добавляет больше функций в соответствии с версией Boost.
Смотрите также
- Автоматический подсчет ссылок
- Приобретение ресурсов - это инициализация (RAII)
- auto_ptr
- Непрозрачный указатель
- Справочник (информатика)
- Boost (библиотеки C ++)
- Толстый указатель
- Вывоз мусора в компьютерном программировании
Рекомендации
- ^ Клайн, Маршалл (сентябрь 1997 г.). «Разделы часто задаваемых вопросов по C ++ Lite, посвященные интеллектуальным указателям с подсчетом ссылок и семантике копирования при записи в разделе часто задаваемых вопросов по управлению бесплатным хранилищем». cis.usouthal.edu. Получено 6 апреля 2018.
- ^ Колвин, Грегори (1994). "предложение по стандартизации countted_ptr в стандартной библиотеке C ++" (PDF). open-std.org. Получено 6 апреля 2018.
- ^ Страуструп, Бьярн. «История C ++: 1979–1991» (PDF). Получено 6 апреля 2018.
- ^ Даль, Оле-Йохан и Найгаард, Кристен (сентябрь 1966 г.). «SIMULA - язык моделирования на основе АЛГОЛА» (PDF). folk.uio.no. Получено 6 апреля 2018.CS1 maint: несколько имен: список авторов (связь)
- ^ «Руководство Taligent по разработке программ, раздел Использование специальных имен для копирования, создания и внедрения подпрограмм».
- ^ Саттер, Херб (20 апреля 2013 г.). «Отчет о поездке: встреча ISO C ++ Spring 2013». isocpp.org. Получено 14 июн 2013.
- ^ а б ISO 14882: 2011 20.7.1
- ^ CERT C ++ Стандарт безопасного кодирования
- ^ ISO 14882: 2014 20.7.1
- ^ boost :: shared_ptr потокобезопасность (формально не распространяется на std :: shared_ptr, но считается, что имеет те же ограничения потоковой передачи)
дальнейшее чтение
- Скотт Мейерс (2014). Эффективный современный C ++. Севастополь, Калифорния: O'Reilly Media. ISBN 978-1491903995. OCLC 884480640.
внешняя ссылка
- Умные указатели. Современный дизайн на C ++: Применение общих шаблонов программирования и проектирования к Андрей Александреску, Аддисон-Уэсли, 2001.
- countptr.hpp. Стандартная библиотека C ++ - Учебное пособие и справочник к Николай М. Йосуттис
- Повышение умных указателей
- Новый C ++: умные (er) указатели. Херб Саттер 1 августа 2002 г.
- Умные указатели - что, почему и какие?. Йонат Шарон
- Обзор умных указателей. Джон М. Длугош
- Умные указатели в Delphi
- Умные указатели в Rust
- Умные указатели в современном C ++