Есть ли повышение :: слабая_интрузивная_поинтер? - PullRequest
13 голосов
/ 08 марта 2010

По старым причинам мне нужно использовать навязчивые указатели, так как мне нужна возможность конвертировать необработанные указатели в умные указатели.

Однако я заметил, что нет слабого навязчивого указателя для повышения. Я нашел разговор об этом в списке тем Boost, но ничего конкретного.

Кто-нибудь знает о поточно-безопасной реализации слабого навязчивого указателя?

Спасибо Рич

Ответы [ 3 ]

10 голосов
/ 08 марта 2010

Это не имеет никакого смысла.

Для уточнения: weak_ptr указывает на тот же экземпляр counter объекта, который shared_ptr делает. Когда shared_ptr выходит из области видимости, экземпляр counter остается (с эффективным счетом в 0), что позволяет экземплярам weak_ptr проверять, действительно ли они указывают на освобожденный объект.

С помощью Intrusive Counting счетчик интегрирован в объект. Когда счет достигает 0, объект обычно либо перерабатывается, либо удаляется ... но дело в том, что счетчик больше не доступен. Обоснование заключается в том, что это обеспечивает более эффективное хранение (1 отдельный блок) и большую скорость (локальность кэша).

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

Идея состоит в том, чтобы отсоединить счетчик от объектов.

class Counted
{
  // bla
private:
  boost::shared_ptr<int> mCounter;
};

Теперь вы можете вернуть слабые ручки:

class WeakHandle
{
public:
  explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {}

  bool expired() const { return mCounter.expired(); }

private:
  boost::weak_ptr<int> mCounter;
  Counted* mObject;
};

Здесь мы отделяем время жизни счетчика от времени жизни объекта, чтобы он пережил разрушение объекта ... частично. Таким образом, weak_ptr эффективно становится возможным.

И, конечно же, используя shared_ptr и weak_ptr, это Безопасный поток;)

5 голосов
/ 27 февраля 2015

Мне не понравился ни один из предыдущих ответов, поэтому:

Нет, я не знаю о реализации, но я думаю, что это возможно. Стандартная реализация shared_ptr содержит два счетчика ссылок, один для «сильных» и один для «слабых» ссылок, и указатель на референт. В реализации intrusive_ptr сильный счет должен быть частью объекта, но слабый не может быть. Похоже, вы могли бы создать «слабый» intrusive_ptr.

Определить хелпер слабого указателя:

template<class X>
class intrusive_ptr_weak_helper {
    long weak_ref_count;
    X *target_instance;
};

Затем запишите это в объект рядом со счетчиком ссылок:

struct X {
    ...
    intrusive_ptr_weak_helper *ref_weak_helper;
    ...
    long ref_count;
    ...
};

При построении X:

ref_count = 0;
ref_weak_helper = NULL;

"Сильный" указатель, intrusive_strong_ptr, идентичен intrusive_ptr, пока не произойдет удаление. Когда счетчик сильных ссылок становится равным нулю (до удаления):

if (ref_weak_helper != NULL) {
    if (ref_weak_helper->weak_ref_count == 0)
        delete ref_weak_helper;
    else
        ref_weak_helper->target_instance = NULL;
}

«Слабая» версия, intrusive_weak_ptr, записывает указатель на слабого помощника, управляя этим счетчиком ссылок и получая доступ к целевому объекту через указатель target_instance. Когда значение weak_ref_count уменьшается до нуля, состояние target_instance определяет, был ли удален помощник.

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

4 голосов
/ 08 марта 2010

Текущая реализация навязчивого указателя использует счетчик ссылок.Таким образом, удаление объекта delete также удаляет счетчик, так что weak_intrusive_pointer никогда не узнает, что объект был удален.

Если вам нужно получить weak_ptr от this, вы, вероятно, ищете boost::enable_shared_from_this<T>.

...