Ответ 1
Основные свойства интеллектуальных указателей
Это легко, когда у вас есть свойства, которые вы можете назначить каждому умному указателю. Существует три важных свойства.
- нет собственности вообще
- передача права собственности
- доля собственности
Первое означает, что интеллектуальный указатель не может удалить объект, потому что он не владеет им. Второй означает, что только один умный указатель может указывать одновременно на один и тот же объект. Если смарт-указатель должен быть возвращен из функций, право собственности переносится на возвращаемый смарт-указатель, например.
Третье означает, что несколько интеллектуальных указателей могут одновременно указывать на один и тот же объект. Это относится и к необработанному указателю, однако у сырых указателей отсутствует важная функция: они не определяют, владеют ли они или нет. Интеллектуальный указатель доли владения удалит объект, если каждый владелец откажется от объекта. Такое поведение часто требуется, поэтому широко распространенные общие интеллектуальные указатели широко распространены.
Некоторые владеющие интеллектуальными указателями не поддерживают ни вторую, ни третью. Поэтому они не могут быть возвращены из функций или переданы где-то в другом месте. Это наиболее подходит для целей RAII
, где интеллектуальный указатель хранится локально и только что создан, поэтому он освобождает объект после его выхода из области видимости.
Доля собственности может быть реализована с помощью конструктора копирования. Это, естественно, копирует умный указатель, и копия, и оригинал будут ссылаться на один и тот же объект. Передача прав собственности в настоящее время не может быть реализована в C++, поскольку нет средств для передачи чего-либо с одного объекта на другой, поддерживаемого языком. Если вы пытаетесь вернуть объект из функции, то происходит то, что объект скопировано. Поэтому умный указатель, который реализует передачу права собственности, должен использовать конструктор копирования для реализации этой передачи права собственности. Однако это, в свою очередь, нарушает его использование в контейнерах, поскольку требования определяют определенное поведение конструктора копирования элементов контейнеров, что несовместимо с этим так называемым "перемещающимся конструктором" поведения этих интеллектуальных указателей.
C++ 1x предоставляет встроенную поддержку передачи права собственности путем введения так называемых "конструкторов перемещения" и "операторов переадресации". Он также поставляется с таким умным указателем передачи собственности, который называется unique_ptr
.
Классификация интеллектуальных указателей
scoped_ptr
- это умный указатель, который не может быть передан или недоступен. Он просто полезен, если вам нужно локально выделять память, но убедитесь, что он освобожден снова, когда он выходит из сферы видимости. Но его можно поменять местами на другой scoped_ptr,, если вы этого хотите.
shared_ptr
- умный указатель, который владеет долей (третий вид выше). Это подсчет ссылок, поэтому он может видеть, когда последняя копия выходит из области действия, а затем освобождает объект.
weak_ptr
- не владеющий интеллектуальным указателем. Он используется для ссылки на управляемый объект (управляемый с помощью shared_ptr) без добавления счетчика ссылок. Обычно вам нужно будет вынуть необработанный указатель из shared_ptr и скопировать его. Но это не будет безопасно, поскольку у вас не было бы возможности проверить, когда объект был фактически удален. Таким образом, weak_ptr предоставляет средства путем ссылки на объект, управляемый shared_ptr. Если вам нужно получить доступ к объекту, вы можете заблокировать его управление (чтобы избежать этого другой поток shared_ptr освобождает его, пока вы используете объект), а затем используйте его. Если weak_ptr указывает на уже удаленный объект, он заметит вас, исключив исключение. Использование weak_ptr наиболее полезно, когда вы циклическая ссылка: подсчет ссылок не может легко справиться с такой ситуацией.
intrusive_ptr
похож на shared_ptr , но он не удерживает счетчик ссылок в shared_ptr , но оставляет приращение/декремент count для некоторых вспомогательных функций, которые должны определяться управляемым объектом. Это имеет то преимущество, что объект с уже ссылкой (который имеет счетчик ссылок, увеличенный внешним механизмом подсчета ссылок) может быть добавлен в intrusive_ptr - поскольку счетчик ссылок больше не является внутренним для интеллектуального указателя, но интеллектуальный указатель использует существующий механизм отсчета ссылок.
unique_ptr
- это передача указателя собственности. Вы не можете скопировать его, но вы можете переместить его, используя конструкторы перемещения C++ 1x:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
Это семантика, которой подчиняется std :: auto_ptr, но из-за отсутствия встроенной поддержки для перемещения она не может обеспечить их без ошибок. unique_ptr автоматически украдет ресурсы из временного другого unique_ptr , который является одной из ключевых особенностей переместить семантику. auto_ptr будет устаревшим в следующем выпуске C++ Standard в пользу unique_ptr. C++ 1x также разрешает набивать объекты, которые только подвижны, но не могут быть скопированы в контейнеры. Таким образом, вы можете использовать unique_ptr в вектор, например. Я остановлюсь здесь и расскажу вам о прекрасной статье об этом, если вы хотите больше узнать об этом.