Предупреждение C ++, когда контейнер уничтожается / модифицируется перед его использованием (использование через ссылку на элемент или итератор) - PullRequest
0 голосов
/ 06 мая 2018

Я начну с недавно возникшей проблемы: у меня был вектор, и я взял его итераторы, я сохранил итераторы (начало, конец), а затем контейнер вышел из области видимости, поэтому уничтожен. Я не помню ни одного предупреждения компилятора. Это была сложная отладка, потому что я получал segfault только тогда, когда запускал его на очень большом наборе данных. Есть ли способ получить ошибки / предупреждения компилятора при использовании итератора / любой ссылки на элемент контейнера после модификации контейнера (увеличения / уменьшения) / уничтожения? Я что-то пропустил? Я думаю, что он так же важен, как и квалификатор const, потому что никто не хочет ссылки на элемент в испорченном контейнере, верно?

Я был вынужден вспомнить ситуацию выше, потому что теперь у меня есть еще одна домашняя работа - создать конкретный контейнер. Вместо ссылки на элемент, который является определенной областью памяти, я должен вернуть ссылку на прокси, потому что после назначения ссылки на прокси часть контейнера должна быть записана на диск. Но просто для информации, это, возможно, не имеет значения, это может быть нормальная ссылка в этом вопросе. Я хочу пометить этот метод, возвращающий ссылку на прокси (или любой метод, возвращающий итератор), как "блокировку" , что будет означать, что контейнер в течение времени жизни ссылки / итератора будет вести себя эффективно как const. (Хотя возможен другой const, допускающий изменение отдельных элементов, но запрещающий изменение контейнера, скажем, свойства макроса, например, будет разрешено возвращать неконстантную ссылку оператором [] для этого объекта «макрос-констант»)

Как мне это сделать на с ++? Существует ли эта концепция в других языках? Или, возможно, почему это не сработает? Как я уже говорил ранее, я предполагаю, что это понятие достаточно общее, потому что первые структуры данных являются строительными блоками любой программы, а вторая - потому что никто не хочет ссылки на элемент в испорченном контейнере.

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

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

Для обработки времени жизни вы можете передать (или вернуть) std::shared_ptr объекту, чтобы убедиться, что он не освобожден, когда все еще используется другой частью программы.

Что касается отладки, в дополнение к статическому анализу, указанному @ user1118321, вы можете использовать очиститель адресов (для clang, compile и link с -fsanitize=address, что в вашем случае приведет к завершению программы с ошибкой AddressSanitizer: heap-use-after-free и довольно подробный отчет о том, где это произошло.

Относительно вашего вопроса о «блокировке», вдохновленного комментарием об использовании Rust @melpomene: вы можете получить семантику, аналогичную заимствованию в ржавчине, переместив (используя std::move()) объект в другую функцию (таким образом "блокируя" это) и затем перемещая это назад, возвращая это. Но тогда вы не можете использовать объект на всех , пока вызываемая функция не вернет ("вернет / разблокирует") объект.

0 голосов
/ 06 мая 2018

Есть ли способ получить ошибки / предупреждения компилятора при использовании итератора / любой ссылки на элемент контейнера после модификации (увеличения / уменьшения) контейнера / уничтожения?

Да. Это называется статическим анализатором. Если вы используете llvm, статический анализатор clang может помочь вам найти некоторые варианты использования памяти после ее освобождения. Есть аналогичные инструменты для других компиляторов. Они также могут рассказать вам и другие полезные вещи, например, когда переменную можно использовать без инициализации, и тому подобное.

Я хочу пометить этот метод, возвращающий ссылку на прокси (или любой метод, возвращающий итератор), как «блокировку», что будет означать, что контейнер во время жизни ссылки / итератора будет вести себя эффективно как const. (Хотя и другое const, допускающее изменение отдельных элементов, но запрещающее изменение контейнера, скажем, свойства макроса,

Я не знаю, как это сделать, чтобы компилятор выдавал вам ошибки или предупреждения в случае изменения контейнера. Но можно заблокировать доступ к ресурсу, используя семафоры или мьютексы . Это остановит другой код от изменения контейнера, пока вы его используете. Вы также можете написать методы изменения контейнера, чтобы они throw исключение, если они вызываются, когда ресурс заблокирован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...