Есть ли boost:: weak_intrusive_pointer?

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

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

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

Спасибо Рич

Ответы

Ответ 1

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

Чтобы уточнить: 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, это Thread Safe;)

Ответ 2

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

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

Ответ 3

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

Нет, я не знаю о реализации, но я думаю, что это возможно. Стандартная реализация 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 определяет, удаляется ли хелпер или нет.

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