2017-02-08 1 views
2

C++ std::shared_ptr<..> может быть пустой и это также может быть нулевым. Обе эти концепции существуют, и они являются не эквивалентом. Кроме того, между этими случаями не всегда подразумевается.Как проверить, является ли опустошить shared_ptr или не имеет никакого отношения

Последний случай является тривиальным для обнаружения, поскольку operator bool обеспечивает именно этот тест. Согласно документам, он «проверяет, сохраняет ли *this ненулевой указатель, т. Е. get() != nullptr».

Есть ли тест для первого случая, случай, когда вещь пусто?

Мое использование для этого довольно простое. У меня есть класс, который имеет статический заводский метод. Внутри статического заводского метода статический локальный shared_ptr экземпляр класса, инициализированный до nullptr. Первый вызов этого фабричного метода создает экземпляр класса и инициализирует статический локальный shared_ptr перед возвратом его копии - это защищено mutex. То, что shared_ptr может храниться на любом, скопированном и переданном, дополнительные копии могут быть приобретены путем дополнительных вызовов статической фабрики, и, наконец, когда все копии будут уничтожены, дебектор shared_ptr уничтожает экземпляр.

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

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

Или это правда, что shared_ptr сбрасывается до nullptr, когда счетчик ссылок падает до нуля и вызывается делектор? Также для пользовательских удалений?

Актуальный: What is the difference between an empty and a null std::shared_ptr in C++?

+1

Как насчет проверки, если [счетчик] (http://en.cppreference.com/w/cpp/memory/shared_ptr/use_count) равен нулю? –

+0

Из-за примечания: «Однако это не гарантируется в многопоточной среде». – Xharlie

+2

Когда я прочитал это, похоже, что после первой инициализации всегда будет счетчик ссылок 1 для некоторого объекта shared_ptr.Если нет, для какого объекта вы могли бы сделать этот гипотетический вызов для определения его текущего состояния? Похоже, что вам может понадобиться поведение weak_ptr. Или, может быть, вы могли бы просто прояснить вопрос, чтобы сделать этот пункт более ясным (например, случай «если что-то пытается получить экземпляр через некоторое время после того, как все предыдущие пользователи отказались от своих ссылок, а общий экземпляр был удален»). – cnettel

ответ

5

Статический экземпляр shared_ptr будет содержать ссылку, так что объект всегда будет иметь количество рефа> = 1, и не будет удален, пока статические очистки не происходят. Как комментирует cnettel, вам нужно std::weak_ptr.

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

Пример:

std::shared_ptr<Obj> instance() { 
    static std::weak_ptr<Obj> instance; 
    static std::mutex lock; 

    std::lock_guard<std::mutex> guard(lock); 

    auto result = instance.lock(); 
    if (!result) { 
     result = std::make_shared<Obj>(); 
     instance = result; 
    } 

    return result; 
} 
+0

Alrighty. Думаю, теперь у меня есть то, что мне сейчас нужно. Я все еще не знаю ответа на фактический вопрос, который я задал *. Кажется, что нет проблемы с потокобезопасностью для этой проблемы, которая мне очень подходит, так как я больше не нуждаюсь в ней. Ta. – Xharlie

+0

Проблема с указанным вопросом заключается в том, что shared_ptr, однажды инициализированный, никогда не может иметь счетчик <= 0, поэтому предварительные условия в вопросе никогда не будут возникать. Проверка того, равен ли счетчик нулю, - это просто проверка, если он был инициализирован, я думаю, что предупреждение в основном говорит о том, что 'if (ptr.use_count() == 0) ptr = new Obj();' не является потокобезопасным, и вам нужен мьютекс. –

+0

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

Смежные вопросы