Почему реализации интеллектуальных указателей C ++ хранят счетчик ссылок в куче вместе с pointee? - PullRequest
5 голосов
/ 14 февраля 2012

Чтение Alexandrescu и wikipipidia Я вижу, что pointee и счетчик ссылок хранятся в куче.Тогда есть упоминание, что подсчет ссылок неэффективен, так как счетчик должен быть размещен в куче?Почему он не хранится в стеке?

Ответы [ 4 ]

9 голосов
/ 14 февраля 2012

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

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

3 голосов
/ 14 февраля 2012

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

1 голос
/ 29 марта 2016

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

Такshared_ptr внутренне сохраняет два указателя: на объект и на счетчик.Псевдокод:

class SharedPointer<T> {
public:
// ...
private:
    T* obj;
    int* counter;
}

Кстати, когда вы создаете объект с std::make_shared, реализация может оптимизировать выделения, выделяя достаточно памяти для хранения как счетчика, так и объекта, а затем создавая их рядом друг с другом.

Этот трюк в крайности дает нам навязчивую схему подсчета ссылок: объект внутренне удерживает свой счетчик и предоставляет функции AddRef и Release для увеличения и уменьшения его.Вы можете использовать навязчивый умный указатель , например boost::intrusive_ptr, который использует этот механизм и, следовательно, не нуждается в выделении другого отдельного счетчика.Это быстрее с точки зрения распределения, но требует внедрения счетчика в определение управляемого класса.

Кроме того, когда вам не нужно совместно использовать владение объектом и нужно только контролировать его время жизни (так что оно разрушаетсякогда функция возвращается), вы можете использовать умный указатель : std::unique_ptr или boost::scoped_ptr.Счетчик вообще не нужен, так как существует только одна копия unique_ptr.

1 голос
/ 14 февраля 2012

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

ЭтоСтоит отметить, что некоторые неэффективности, связанные с размещением счетчика ссылок в куче, можно преодолеть, сохранив его «вместе» с самим объектом.В boost это можно сделать с помощью boost :: make_shared (для shared_ptr) или boost :: intrusive_ptr .

...