Почему В Стандартной Библиотеке Нет Возможности Бороться С Висячими Ссылками И Как Это Исправить?

После появления умных указателей в стандартной библиотеке C++ проблема управления временем жизни объекта была решена.

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

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

В других случаях используйте «старые и опасные» необработанные указатели.

Как разработчики языка предлагают решить эту проблему? На сайте Рекомендации CppCore есть несколько интересных документов( Здесь И Здесь ).

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

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

Я не согласен с этой позицией и вот мои причины:

  1. Статический анализ не сможет уловить все проблемы.

    Сами авторы статей говорят, что иногда придется пометить некоторые проекты как безопасные, оставив вопрос корректности кода на совести разработчика.

  2. Чтобы статический анализ работал, необходима поддержка со стороны компиляторов.

    Когда он появится, неизвестно.

  3. Статический анализ не позволяет иметь слабые указатели, не владеющие объектом (аналог слабого_ptr, который обнуляется при удалении объекта).

  4. Реализация таких указателей нарушает принцип нулевых накладных расходов — это правда.

    Но, на мой взгляд, этот принцип нарушает и Shared_ptr, т. к.

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

    В любом случае стандартная библиотека предоставляет классы с четко определенными характеристиками, а программист решает, подходят ему эти классы или нет.

По моему мнению, стандартная библиотека должна предоставлять классы для всех основных сценариев программирования.

Бесхозные указатели и доступ к висячим ссылкам — большая и до сих пор нерешенная тема в C++.

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

В вашем проекте РГБ Я попробовал реализовать такой указатель.

Основная идея не нова: нужен объект, который при уничтожении будет уведомлять указатели о факте удаления.

Таким образом, у нас есть два класса:

  1. rsl::track::отслеживаемый — класс, который уведомляет указатели при их удалении.

  2. rsl::track::указатель — фактический указатель, не являющийся владельцем.

Когда rsl::track::указатель указывает на то же самое rsl::track::отслеживаемый объекта, они упорядочены в двусвязный список.

Указатель на начало списка содержится в rsl::track::отслеживаемый .

Таким образом, создание указателей занимает постоянное время.

Размер р sl::track::отслеживаемый представляет собой один указатель, и rsl::track::указатель — 4 указателя (указатель на объект, два указателя для организации списка и еще один для реализации полиморфного поведения).

Возможно есть более оптимальная организация указателей, если кто знает, подскажите.

Кроме того, эта реализация не является потокобезопасной; для обеспечения работы в разных потоках придется добавить std::atomic_flag и замедлить модификацию указателей.

Более того, с появлением контейнеры с поддержкой распределителя , появилась возможность реализовать распределитель , что позволяет использовать rsl::track::указатель со стандартными контейнерами.

Основная идея заключается в том, что теперь все выделения в контейнерах выполняются экземпляром распределителя, хранящимся в контейнере, или его шаблонной копией, и мы можем хранить rsl::track::отслеживаемый в распределителе и передать его копиям.

В тесты приведены примеры работы с основными стандартными контейнерами, включая std::array, а также уникальный_ptr .

В заключение я хочу привести еще один сценарий, в котором rsl::track::указатель будет полезно.

Это ситуации похожие удалить это .

Обычно это происходит косвенно при вызове кода, функтора или внешнего по отношению к объекту сигнала.

Ошибки такого типа встречаются редко, но их трудно обнаружить.

Для таких случаев (и любых других проблем с доступом по висячей ссылке) используйте такие инструменты, как дезинфицирующие средства Google , которые позволяют выявлять такие проблемы.

Но у этих средств есть свои недостатки:

  1. Они работают не везде (не на всех платформах).

  2. Необходимо инструментирование кода — код отличается от производственного.

  3. Аналога слабого_ptr, указатель которого сбрасывается при удалении объекта, не существует.
  4. Определяет время и место доступа на основе недопустимого указателя.

    Хотя, как правило, более интересный момент — это когда удаляется объект, на который есть указатели.

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

Надеюсь, библиотека будет полезна разработчикам C++.

Возможно, есть и другие способы решения подобных проблем, буду рад услышать их в комментариях.

P.S. Еще раз для удобства привожу ссылку на код библиотеки РГБ .

Теги: #c++ #программирование #открытый исходный код #C++

Вместе с данным постом часто просматривают: