Подтвердить что ты не робот

Почему lib_ptr нельзя построить из unique_ptr?

Если я правильно понимаю, weak_ptr не увеличивает счетчик ссылок управляемого объекта, поэтому он не представляет права собственности. Он просто позволяет вам получить доступ к объекту, срок службы которого управляется кем-то другим. Поэтому я не понимаю, почему weak_ptr невозможно построить из unique_ptr, но только shared_ptr.

Может кто-нибудь коротко объяснить это?

4b9b3361

Ответ 1

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

Чтобы проиллюстрировать это, просмотрите два фрагмента кода:

std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);

{
*(w.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared  to keep it alive
}

Теперь с вашим предложением:

std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);

{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it! 
}

Как уже говорилось, вы можете предположить, что существует только один unique_ptr, и вы все еще можете разыскивать weak_ptr (без создания другого unique_ptr), тогда проблем нет. Но в чем же разница между unique_ptr и shared_ptr с одной ссылкой? или более того, в чем разница между регулярными unique_ptr и C-указателями get с помощью get?

weak_ptr не для "общих не владеющих ресурсами", он имеет очень специфическую работу. Основная цель weak_ptr - предотвратить круговое отображение shared_ptr, которое приведет к утечке памяти. Что-то еще нужно сделать с помощью простых unique_ptr и shared_ptr.

Ответ 2

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

С shared_ptr, что-то есть то, что содержит счетчик ссылок. Но с unique_ptr, нет счетчика ссылок, поэтому нет ничего, что содержит счетчик ссылок, поэтому ничего не должно продолжаться, когда объект ушел. Так что нет ничего для weak_ptr для ссылки.

Также не было бы разумного способа использовать такой weak_ptr. Чтобы использовать его, вы должны иметь какой-то способ гарантировать, что объект не был уничтожен во время его использования. Легко с shared_ptr - то, что делает a shared_ptr. Но как вы это делаете с помощью unique_ptr? У вас, очевидно, не может быть двух из них, и что-то еще должно уже владеть объектом или оно было бы уничтожено, так как ваш указатель слаб.

Ответ 3

A shared_ptr состоит из двух частей:

  • указательный объект
  • объект счетчика ссылок

Как только счетчик ссылок падает до нуля, объект (# 1) удаляется.

Теперь weak_ptr должен знать, существует ли объект. Для этого он должен иметь возможность видеть объект подсчета ссылок (# 2), если он не равен нулю, он может создать shared_ptr для объекта (путем увеличения количества ссылок). Если счетчик равен нулю, он вернет пустой shared_ptr.

Теперь подумайте, можно ли удалить объект count count (# 2)? Мы должны подождать, пока объект shared_ptr OR weak_ptr не будет ссылаться на него. Для этого объект отсчета ссылок содержит два подсчета ссылок, сильное ref и слабое ref. Объект подсчета ссылок будет удален только тогда, когда оба его значения равны нулю. Это означает, что часть памяти может быть освобождена только после того, как исчезнут слабые ссылки (это означает скрытый недостаток с make_shared).

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

Ответ 4

Понятно, что ничего не мешает реализации, где weak_ptr предоставляет только доступ, а unique_ptr управляет временем жизни. Однако есть проблемы с этим:

  • unique_ptr не использует подсчет ссылок для начала. Добавление структуры управления для управления слабыми ссылками возможно, но требует дополнительного динамического распределения. Поскольку unique_ptr должен избегать каких-либо (!) Служебных затрат времени выполнения над необработанным указателем, эти служебные данные неприемлемы.
  • Чтобы использовать объект, на который ссылается weak_ptr, вам нужно извлечь из него "реальную" ссылку, которая сначала проверит, что указатель не истек первым, а затем предоставит вам эту реальную ссылку (a shared_ptr в этом случае). Это означает, что вы внезапно имеете вторую ссылку на объект, который должен быть уникальным, что является рецептом ошибок. Это невозможно устранить, возвращая смешанный полусильный указатель, который только временно задерживает возможное разрушение указателя, потому что вы могли бы также сохранить этот, тоже побеждая идею unique_ptr.

Просто интересно, какую проблему вы пытаетесь решить, используя weak_ptr здесь?

Ответ 5

Никто еще не упомянул о аспекте производительности проблемы, поэтому позвольте мне забросить мои $0,02 дюйма.

weak_ptr должен каким-то образом знать, когда соответствующие shared_ptr все вышли из области действия, и выделенный объект был освобожден и уничтожен. Это означает, что shared_ptr необходимо каким-то образом сообщить об уничтожении по отношению к каждому weak_ptr одному и тому же объекту. У этого есть определенная стоимость - например, глобальная хеш-таблица должна быть обновлена, где weak_ptr получает адрес из (или nullptr, если объект уничтожен).

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

Однако целью unique_ptr является предоставление класса нулевой стоимости класса абстракции в стиле RAII. Следовательно, он не должен брать на себя никакой другой стоимости, чем стоимость delete ing (или delete[] ing) динамически распределенного объекта. Задержка, налагаемая, например, закрытым или иным образом защищенным доступом к хеш-таблице, может быть сопоставима со стоимостью освобождения, однако это нежелательно в случае unique_ptr.

Ответ 6

Похоже, что все пишут здесь о std:: weak_ptr, но не о слабой концепции poiner, которая, по моему мнению, является тем, о чем автор просит

Я думаю, что никто не упомянул, почему стандартная библиотека не предоставляет weak_ptr для unique_ptr. Слабый указатель CONCEPT не отказывается от использования unique_ptr. Слабый указатель - это только информация, если объект уже удален, поэтому это не волшебный, а очень простой обобщенный шаблон наблюдателя.

Это из-за безопасности потоков и согласованности с shared_ptr.

Вы просто не можете гарантировать, что ваш weak_ptr (созданный из unique_ptr, существующий в другом потоке) не будет уничтожен во время вызова метода на заостренном объекте. Это потому, что weak_ptr должен быть совместим с std:: shared_ptr, которые гарантируют безопасность потоков. Вы можете реализовать weak_ptr, который корректно работает с unique_ptr, но только в том же методе блокировки потоков в этом случае будет ненужным. Вы можете проверить источники хрома для базы:: WeakPtr и base:: WeakPtrFactory - вы можете использовать его свободно с unique_ptr. Хром слабый код указателя, скорее всего, основан на уничтожении последнего члена - вам нужно добавить factory в качестве последнего члена, и после этого я считаю, что WeakPtr сообщается об удалении объекта abut (я не уверен на 100%) - t выглядит так сложно реализовать.

В целом использование unique_ptr со слабой концепцией указателя ОК IMHO.

Ответ 7

Может быть полезно различить причины для предпочтения a unique_ptr над a shared_ptr.

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

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

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