Где обычно хранится счетчик ссылок на объект? - PullRequest
1 голос
/ 20 июня 2019

Если у нас есть некоторый класс интеллектуальных указателей, который может взять произвольный объект и предоставить указатель с подсчетом ссылок, как нам на самом деле хранить целое число, которое подсчитывает ссылки?Счетчик ссылок должен быть общим для всех экземпляров класса интеллектуальных указателей, которые указывают на один и тот же объект.

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

Ответы [ 3 ]

3 голосов
/ 20 июня 2019

Он «обычно хранится» в любом месте, необходимом для проектирования объекта.Интрузивные умные указатели требуют T, с которым они используются, чтобы обеспечить хранилище для подсчета ссылок.Вот что делает их «навязчивыми»;они вторгаются в объект.

Указанный вами дизайн "может взять произвольный объект".Таким образом, навязчивый дизайн исключен из таблицы.

Поскольку многие экземпляры интеллектуального указателя должны иметь доступ к одному и тому же объекту подсчета ссылок, этот счетчик ссылок должен быть независимым от любого одного экземпляра.И поскольку он также должен быть независимым от T, он должен быть объектом, время жизни которого не зависит ни от T, ни от любого экземпляра интеллектуального указателя, который на него ссылается.

Таким образом, интеллектуальный указатель при получении права собственностиT, также должен создать объект подсчета ссылок для управления им.Как правило, это делается с помощью кучи, выделяющей такой объект.Копии интеллектуального указателя также получают указатель на счетчик ссылок.

По этой же причине недопустимо, чтобы два разных конструктора std::shared_ptr претендовали на владение одним и тем же T*.Вы можете скопировать из shared_ptr, которому уже принадлежит T*, но вы не можете просто передать сам T* непосредственно в конструктор.Поскольку T не имеет доступа к счетчику ссылок, конструктор shared_ptr не будет знать, что им владеет кто-то другой, поэтому он создаст второй блок подсчета ссылок.

1 голос
/ 20 июня 2019

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

(Блок управления иобъект может жить в том же распределении, если используется std::make_shared)

То, что вы описываете во втором абзаце, также существует, например: оно называется intrusive_ptr в Boost.

0 голосов
/ 20 июня 2019

Существует множество стратегий для хранения счетчика ссылок, в зависимости от того, какие операции вы хотите поддерживать.

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

Другой вариант - ссылка на ссылку , в которой нет явной ссылкисосчитать.Вместо этого вы продвигаете круговой список с двойными связями через все умные указатели.При добавлении нового умного указателя к объекту этот умный указатель вставляется в связанный список, а при удалении умного указателя умный указатель выделяется из связанного списка.Это устраняет необходимость во вспомогательном выделении (если, скажем, вам не нужно пользовательское удаление) и улучшает локальность, но удорожает определение точного количества ссылок.Довольно редко требуется точное количество ссылок, поэтому этот компромисс часто бывает разумным.

...