Слабая ссылка на scoped_ptr?

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

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers

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

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

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

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

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

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

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

Ура, Шейн

4 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам