Из Википедии, бесплатной энциклопедии
  (Перенаправлено с Weak ptr )
Перейти к навигации Перейти к поиску

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

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

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

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

История [ править ]

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

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

… Значения

элементов могут быть сохранены и извлечены путем присвоений и ссылок на переменные элемента и другими способами.

Язык содержит механизм, позволяющий сделать атрибуты процесса доступными извне, т. Е. Изнутри других процессов. Это называется удаленным доступом. Таким образом, процесс представляет собой структуру данных, на которую можно ссылаться.

Стоит отметить сходство между процессом, тело активности которого является фиктивным оператором, и концепцией записи, недавно предложенной К. А. Хоаром и Н. Виртом.

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

Особенности [ править ]

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

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

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

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

станд :: unique_ptr < SomeType >  ObviousFunction ();

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

Создание новых объектов [ править ]

Чтобы облегчить выделение

std :: shared_ptr < SomeType >

Представлен C ++ 11 :

Auto  сек  =  станд :: make_shared < SomeType > ( конструктор ,  параметры ,  здесь );

и аналогично

станд :: unique_ptr < SOME_TYPE >

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

авто  у  =  станд :: make_unique < SomeType > ( конструктор ,  параметры ,  здесь );

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

unique_ptr [ править ]

C ++ 11 представляет std::unique_ptr, определенный в заголовке <memory>. [7]

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

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

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

shared_ptr и weak_ptr [ править ]

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

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

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

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

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

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

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

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

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

См. Также [ править ]

  • Автоматический подсчет ссылок
  • Приобретение ресурсов - это инициализация (RAII)
  • auto_ptr
  • Непрозрачный указатель
  • Справочник (информатика)
  • Boost (библиотеки C ++)
  • Толстый указатель
  • Сборка мусора в компьютерном программировании

Ссылки [ править ]

  1. Перейти ↑ Kline, Marshall (сентябрь 1997 г.). «Разделы часто задаваемых вопросов по C ++ Lite, посвященные интеллектуальным указателям с подсчетом ссылок и семантике ссылок на копирование при записи в разделе часто задаваемых вопросов по управлению бесплатным хранилищем» . cis.usouthal.edu . Проверено 6 апреля 2018 .
  2. ^ Колвин, Грегори (1994). «предложение по стандартизации countted_ptr в стандартной библиотеке C ++» (PDF) . open-std.org . Проверено 6 апреля 2018 .
  3. ^ Страуструп, Бьярн. «История C ++: 1979–1991» (PDF) . Проверено 6 апреля 2018 .
  4. Даль, Оле-Йохан и Найгаард, Кристен (сентябрь 1966 г.). «SIMULA - язык моделирования на основе АЛГОЛА» (PDF) . folk.uio.no . Проверено 6 апреля 2018 . CS1 maint: несколько имен: список авторов ( ссылка )
  5. ^ «Руководство Taligent по разработке программ, раздел Использование специальных имен для копирования, создания и принятия подпрограмм» .
  6. Саттер, Херб (20 апреля 2013 г.). «Отчет о поездке: встреча ISO C ++ Spring 2013» . isocpp.org . Проверено 14 июня 2013 года .
  7. ^ а б ISO 14882: 2011 20.7.1
  8. ^ CERT C ++ Стандарт безопасного кодирования
  9. ^ ISO 14882: 2014 20.7.1
  10. ^ boost :: shared_ptr потокобезопасность (формально не распространяется на std :: shared_ptr, но считается, что имеет те же ограничения потоковой передачи)

Дальнейшее чтение [ править ]

  • Скотт Мейерс (2014). Эффективный современный C ++ . Севастополь, Калифорния: O'Reilly Media . ISBN 978-1491903995. OCLC  884480640 .

Внешние ссылки [ править ]

  • Умные указатели . Современный C ++ дизайн : Обобщенное программирование и шаблоны проектирования Прикладного по Александреске , Addison-Wesley, 2001.
  • countptr.hpp . C ++ Стандартная библиотека - Учебник и справочник по Nicolai M. Josuttis
  • Повышение умных указателей
  • Новый C ++: умные (er) указатели . Херб Саттер, 1 августа 2002 г.
  • Умные указатели - что, почему, что? . Йонат Шарон
  • Обзор умных указателей . Джон М. Длугош
  • Умные указатели в Delphi
  • Умные указатели в Rust
  • Умные указатели в современном C ++