Интеллектуальный указатель

редактировать

В информатике интеллектуальный указатель - это абстрактный тип данных, который имитирует указатель, обеспечивая при этом дополнительные функции, такие как автоматическое управление памятью или проверка границ. Такие функции предназначены для уменьшения количества ошибок вызвал неправильным использованием указателей при сохранении эффективности. Интеллектуальные указатели обычно отслеживают память, на которую они указывают, а также могут использоваться для управления другими ресурсами, такими как сетевые соединения и дескрипторы файлов. Интеллектуальные указатели были впервые популяризированы в языке программирования C ++ в первой половине 1990-х годов как опровержение критики отсутствия в C ++ автоматической сборки мусора.

Неправильное использование указателей может быть основным источником ошибок. Интеллектуальные указатели предотвращают большинство ситуаций утечек памяти, делая освобождение памяти автоматическим. В более общем смысле, они делают разрушение объекта автоматическим: объект, управляемый интеллектуальным указателем, автоматически уничтожается (finalized, а затем освобождается), когда уничтожается последний (или единственный) владелец объекта., например, потому что владельцем является локальная переменная, а выполнение оставляет переменную в области видимости. Умные указатели также устраняют висячие указатели, откладывая уничтожение до тех пор, пока объект не перестанет использоваться.

Если язык поддерживает автоматическую сборку мусора (например, Java или C # ), то интеллектуальные указатели не нужны для аспектов восстановления и безопасности управления памятью, однако полезны для других целей, таких как управление размещением структуры данных кеша и управление ресурсами таких объектов, как дескрипторы файлов или сетевые сокеты.

. существуют типы умных указателей. Некоторые работают с подсчетом ссылок, другие путем присвоения права собственности на объект одному указателю.

Содержание
  • 1 История
  • 2 Возможности
  • 3 Создание новых объектов
  • 4 unique_ptr
  • 5 shared_ptr и weak_ptr
  • 6 См. Также
  • 7 Ссылки
  • 8 Дополнительная литература
  • 9 Внешние ссылки
История

Несмотря на то, что C ++ популяризировал концепцию интеллектуальных указателей, особенно разновидность подсчитываемых ссылок, непосредственного предшественника одного из языков, которые вдохновили C ++ дизайн имел ссылки с подсчетом ссылок, встроенные в язык. C ++ частично был вдохновлен Simula67. Предком Simula67 была Simula I. Постольку, поскольку элемент Simula I аналогичен указателю C ++ без нуля, и поскольку процесс Simula I с фиктивным оператором, поскольку его тело действия аналогично структуре C ++ (которая сама аналогична записи CAR Hoare в то время) - современная работа 1960-х годов), в Simula I были элементы с подсчетом ссылок (т. е. выражения-указатели, которые содержат косвенное указание) на процессы (т. е. записи) не позднее сентября 1965 г., как показано в приведенных ниже абзацах.

На процессы можно ссылаться. индивидуально. Физически ссылка на процесс - это указатель на область памяти, содержащую локальные для процесса данные и некоторую дополнительную информацию, определяющую его текущее состояние выполнения. Однако по причинам, указанным в разделе 2.2, ссылки на процессы всегда косвенные, через элементы, называемые элементами. Формально ссылка на процесс - это значение выражения типа element... ….. значения элементов могут быть сохранены и извлечены путем присвоений и ссылок на переменные элемента и другими способами... Язык содержит механизм для обеспечение доступа к атрибутам процесса извне, т. е. изнутри других процессов. Это называется удаленным доступом. Таким образом, процесс является структурой данных, на которую можно ссылаться...

Стоит отметить сходство между процессом, тело действия которого является фиктивным оператором, и концепцией записи, недавно предложенной CAR Hoare и N. Wirth

Поскольку C ++ заимствовал Подход Simula к распределению памяти - ключевое слово new при выделении процесса / записи для получения нового элемента для этого процесса / записи - неудивительно, что C ++ в конечном итоге воскресил в Simula механизм интеллектуального указателя с подсчетом ссылок внутри элемента. также.

Возможности

В C ++ интеллектуальный указатель реализован как класс шаблона, который имитирует с помощью перегрузки оператора поведение традиционный (необработанный) указатель (например, разыменование, присваивание), обеспечивая при этом дополнительные функции управления памятью.

Интеллектуальные указатели могут облегчить преднамеренное программирование, выражая в типе то, как будет управляться память референта указателя. Например, если функция C ++ возвращает указатель, невозможно узнать, должен ли вызывающий объект удалить память референта, когда вызывающий закончит с информацией.

SomeType * AmbiguousFunction (); // Что делать с результатом?

Традиционно для устранения неоднозначности использовались соглашения об именах, что является трудоемким подходом, подверженным ошибкам. C ++ 11 представил способ гарантировать правильное управление памятью в этом случае, объявив функцию, возвращающую unique_ptr,

std :: unique_ptr ObviousFunction ();

Объявление типа возвращаемого значения функции как unique_ptrявно указывает на то, что вызывающий объект становится владельцем результата, а среда выполнения C ++ гарантирует, что память будет освобождена автоматически. До C ++ 11, unique_ptr можно было заменить на auto_ptr.

Создание новых объектов

Для упрощения выделения

std :: shared_ptr 

C ++ 11 введено:

auto s = std :: make_shared (конструктор, параметры, здесь);

и аналогично

std :: unique_ptr 

Начиная с C ++ 14 можно использовать:

auto u = std :: make_unique (конструктор, параметры, здесь) ;

Практически во всех случаях предпочтительно использовать эти возможности вместо новогоключевого слова :

unique_ptr

C ++ 11 вводит std: : unique_ptr, определенный в заголовке .

A unique_ptr, является контейнером для необработанного указателя, которым, как говорят, принадлежит unique_ptr. unique_ptrявно предотвращает копирование содержащегося в нем указателя (как это произошло бы при обычном назначении), но функцию std :: moveможно использовать для передачи владения содержащимся указателем другому unique_ptr. unique_ptrне может быть скопирован, поскольку его конструктор копирования и операторы присваивания явно удалены.

std :: unique_ptr p1 (новый int (5)); std :: unique_ptr p2 = p1; // Ошибка компиляции. std :: unique_ptr p3 = std :: move (p1); // Передает право собственности. p3 теперь владеет памятью, а p1 имеет значение nullptr. p3.reset (); // Удаляет память. p1.reset (); // Ничего не делает.

std::auto_ptr является устаревшим в C ++ 11 и полностью удален из C ++ 17. Конструктор копирования и операторы присваивания auto_ptrфактически не копируют сохраненный указатель. Вместо этого они передают его, оставляя предыдущий объект auto_ptrпустым. Это был один из способов реализации строгого владения, так что только один объект auto_ptrможет владеть указателем в любой момент времени. Это означает, что auto_ptrне следует использовать там, где требуется семантика копирования. Поскольку auto_ptrуже существовал с его семантикой копирования, его нельзя было обновить до указателя только для перемещения без нарушения обратной совместимости с существующим кодом.

shared_ptr и weak_ptr

В C ++ 11 представлены std :: shared_ptrи std :: weak_ptr, определенные в заголовке . C ++ 11 также представляет std :: make_shared(std :: make_uniqueбыл представлен в C ++ 14) для безопасного выделения динамической памяти в парадигме RAII.

A shared_ptr- это контейнер для необработанного указателя. Он поддерживает подсчет ссылок владение содержащимся в нем указателем во взаимодействии со всеми копиями shared_ptr. Объект, на который ссылается содержащийся в нем необработанный указатель, будет уничтожен тогда и только тогда, когда будут уничтожены все копии shared_ptr.

std :: shared_ptr p0 (новый int (5)); // Допустимо, выделяет 1 целое число и инициализирует его значением 5. std :: shared_ptr p1 (new int [5]); // Допустимо, выделяет 5 целых чисел. std :: shared_ptr p2 = p1; // Теперь память принадлежит обоим. p1.reset (); // Память все еще существует из-за p2. p2.reset (); // Освобождает память, так как никто другой не владеет памятью.

A weak_ptr- контейнер для необработанного указателя. Он создается как копия shared_ptr. Существование или уничтожение weak_ptrкопий shared_ptrне влияет на shared_ptrили другие его копии. После того, как все копии shared_ptrбыли уничтожены, все копии weak_ptrстанут пустыми.

std :: shared_ptr p1 = std :: make_shared (5); std :: weak_ptr wp1 {p1}; // p1 владеет памятью. {std :: shared_ptr p2 = wp1.lock (); // Теперь p1 и p2 владеют памятью. // p2 инициализируется слабым указателем, поэтому вы должны проверить, // существует ли еще память! если (p2) {DoSomethingWith (p2); }} // p2 уничтожен. Память принадлежит p1. p1.reset (); // Освободить память. std :: shared_ptr p3 = wp1.lock (); // Памяти больше нет, поэтому мы получаем пустой shared_ptr. if (p3) {// код не выполнит ActionThatNeedsALivePointer (p3); }

Поскольку реализация shared_ptrиспользует подсчет ссылок, циклические ссылки потенциально представляют проблему. Круговую цепочку shared_ptrможно разорвать, изменив код так, чтобы одна из ссылок была weak_ptr.

. Несколько потоков могут безопасно одновременно обращаться к разным shared_ptrи weak_ptrобъекты, которые указывают на один и тот же объект.

Указанный объект должен быть защищен отдельно, чтобы гарантировать, что потокобезопасность.

shared_ptrи weak_ptrоснованы на версии, используемые библиотеками Boost. Технический отчет C ++ 1 (TR1) сначала представил их в стандарте, как общие утилиты, но C ++ 11 добавляет больше функции, соответствующие версии Boost.

См. Также
Ссылки
Дополнительная литература
Внешние ссылки
Последняя правка сделана 2021-06-08 06:34:55
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте