Слабая ссылка на scoped_ptr? - PullRequest
1 голос
/ 28 июля 2011

Обычно я следую руководству по стилю Google, которое, как мне кажется, хорошо согласуется с тем, как я вижу вещи. Я также почти исключительно использую boost :: scoped_ptr, чтобы только один менеджер владел определенным объектом. Затем я передаю голые указатели, идея в том, что мои проекты структурированы таким образом, что менеджеры указанных объектов всегда уничтожаются после уничтожения объектов, которые их используют.

http://google -styleguide.googlecode.com / SVN / багажник / cppguide.xml # Smart_Pointers

Это все замечательно, однако меня укусила небольшая неприятная ошибка, связанная с тем, что владелец просто так удалился до того, как объекты, которые его использовали, были удалены.

Теперь, прежде чем все подпрыгнут, что я дурак для этого паттерна, почему бы мне просто не использовать shared_ptr? и т.д., учтите, что я не хочу иметь неопределенную семантику владельца. Хотя shared_ptr поймал бы этот конкретный случай, он отправляет неверное сообщение пользователям системы. Там написано: «Я не знаю, кому это принадлежит, это может быть ты!»

Что бы мне помогло, был бы слабый указатель на указатель в области видимости. По сути, указатель с областью действия, имеющий список слабых ссылок, которые обнуляются, когда указатель с областью действия разрушается. Это позволит использовать семантику единого владельца, но даст возможность использующим объектам уловить проблему, с которой я столкнулся.

Таким образом, за счет дополнительного указателя 'weak_refs' для scoped_ptr и дополнительного указателя для 'next_weak_ptr' в weak_ptr, это сделало бы аккуратного маленького единственного владельца структурой с несколькими пользователями.

Возможно, это может быть просто функция отладки, поэтому в «выпуске» вся система просто превращается в scoped_ptr обычного размера и стандартный одиночный указатель для слабой ссылки.

Итак ..... мои вопросы после всего этого:

  1. Есть ли такой указатель / паттен уже в stl / boost, что я отсутствует, или я должен просто свернуть свой собственный?
  2. Есть ли лучший способ все еще отвечает моей единственной цели владения?

Ура, Шейн

Ответы [ 4 ]

6 голосов
/ 28 июля 2011

2. Есть ли лучший способ, который по-прежнему отвечает моей единственной цели владения?

Используете ли shared_ptr, но как член класса, чтобы он был частью инвариантаэтого класса и общедоступного интерфейса предоставляет только способ получения weak_ptr.

. Конечно, патологический код может затем сохранять свои собственные shared_ptr из этого weak_ptr столько, сколько они захотят.Я не рекомендую пытаться защищаться от Макиавелли здесь, только от Мерфи (используя слова Саттера).С другой стороны, если ваш вариант использования асинхронный, то тот факт, что блокировка weak_ptr возвращает shared_ptr, может быть особенностью!

3 голосов
/ 28 июля 2011

Хотя shared_ptr мог бы обнаружить этот конкретный случай, он отправляет неверное сообщение пользователям системы. Там написано: «Я не знаю, кому это принадлежит, это может быть ты!»

shared_ptr не означает "я не знаю, кому это принадлежит". Это означает " Мы владеем этим". Тот факт, что одно лицо не имеет исключительного права собственности, не означает, что любой может владеть им.

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

Есть ли такой указатель / шаблон уже в stl / boost, который мне не хватает, или я должен просто свернуть свой собственный?

Вы можете использовать shared_ptr точно так же, как и scoped_ptr. То, что им можно делиться, не означает, что у вас есть , чтобы поделиться им. Это был бы самый простой способ работать; просто сделайте единоличное владение соглашением, а не правилом, установленным API.

Однако, если вам нужен указатель с одним владельцем, но со слабыми указателями, в Boost его нет.

1 голос
/ 28 июля 2011

Я не уверен, что слабые указатели так сильно помогут. Как правило, если компонент X использует другой компонент Y, X должен быть проинформирован о смерти Y, не только чтобы обнулить указатель, но, возможно, удалить его из списка, или изменить режим работы, чтобы он больше не нуждался в объект. Много лет назад, когда я впервые запустил C ++, была волна деятельность пытается найти хорошее общее решение. (Проблема была называется управление отношениями тогда.) Насколько я знаю, ничего хорошего было найдено общее решение; по крайней мере, каждый проект, над которым я работал использовал решение ручной сборки, основанное на шаблоне Observer.

У меня действительно было ManagedPtr на моем сайте, когда он еще работал, который вел себя о том, что вы описываете. На практике, за исключением случай, который привел к этому, я никогда не нашел реального использования для него, потому что Уведомление всегда было необходимо. Это не сложно реализовать, однако; управляемый объект происходит от класса ManagedObject и получает все указатели (ManagedPtr, а не необработанные указатели), которые он раздает. Сам указатель зарегистрирован в классе ManagedObject, а деструктор класса ManagedObject посещает их всех и "отключает" их путем установки фактического указателя на ноль. И, конечно же, ManagedPtr имеет функцию isValid, так что код клиента может быть проверен перед разыменования. Это работает хорошо (независимо от того, как объект управляет & mdash; большинство объектов моей сущности "владеют" собой и делают delete this - это ответ на какой-то конкретный ввод), за исключением того, что вы склонны утечка неверна ManagedPtr (например, всякий раз, когда клиент держит указатель в каком-либо контейнере, потому что он может иметь более одного), и клиенты все еще не уведомлены, если им нужно предпринять какие-то действия, когда ваш объект умирает.

0 голосов
/ 28 июля 2011

Если вы используете QT, QPointer в основном слабый указатель на QObject. Он подключается к событию «Я только что был уничтожен» в указанном значении и автоматически аннулирует себя при необходимости. Это серьезно здоровенная библиотека, которую можно использовать для отслеживания ошибок, хотя, если вы еще не перепрыгиваете через QT.

...