0
int *varr = new int(5);

for (unsigned int i = 0; i < 5; ++i) {
    varr[i] = i;
}
  • Ну не выполняет он проверку выхода за пределы диапазона. А у вас вообще непонятно - что проверять? Один указатель создали, по другому пишете - что тут не так? – Harry Oct 27 '18 at 09:36
  • Исправил, т.е ошибка изза того что new не проверяет выход за пределы, и условно я могу выстрелить себе в ногу пользуясь переменной как массивом? – Вфыавыфа Фываывавфыа Oct 27 '18 at 09:42
  • 1
    А при чем тут new? Выход за пределы массива происходит внутри цикла. Заботиться о том, чтобы такого не происходило - обязанность программиста. – user7860670 Oct 27 '18 at 09:48
  • Да запросто. Это язык, который эффективность ставит выше ошибок программиста :) – Harry Oct 27 '18 at 09:48
  • А почему компилятор позволяет работать с динамической переменной как с массивом? это же обычный тип int – Вфыавыфа Фываывавфыа Oct 27 '18 at 09:52
  • Нет, это указатель на int. Соответственно количество элементов, на которое он указывает, никак не ограничено, а оператор индексирования p[i] работает эквивалентно *(p + i) – user7860670 Oct 27 '18 at 10:03
  • благодарю, т.е компилятору пофиг переменная это или массив, ошибки возникнут только при выполнении? – Вфыавыфа Фываывавфыа Oct 27 '18 at 10:11
  • Переменная здесь только varr, но она является указателем, а указывает она на массив из нескольких int, на массив из одного int или на отдельное значение int, компилятор никак не контролирует. А ошибка тут сразу запарывает весь код еще на этапе компиляции, так как некорретный доступ к памяти является Неопределенным Поведением. То есть программа может не скомпилироваться совсем или выдавать рандомные результаты при работе. – user7860670 Oct 27 '18 at 10:17
  • благодарствую. +1 вам в карму:) – Вфыавыфа Фываывавфыа Oct 27 '18 at 10:23
  • Добавлю к вышенаписанному: если вам нужно отслеживать подобные ошибки, вам может помочь cppcheck и sinitizer. Первая поможет отлавливать похожие ошибки во время компиляции (ну или во время проверки кода), а вторая крашанет вашу прогу во время выполнения и выведет ошибки вроде обращения по невалидному указателю,выходу за пределы массива и утечек памяти. – Andrej Levkovitch Oct 27 '18 at 10:24
  • Массивы переменной длины в C++ так и не сделали, даже запретили. Результатом оператора new[] всё равно возвращается указатель на первый элемент. Чтобы у вас была гарантия отсутствия баг-описок, пользуйтесь std::vector vec(5) – AlexGlebe Oct 27 '18 at 12:02
  • @AlexGlebe Ага, хорошая такая гарантия. В цикле выход за пределы массива как был, так и останется. – user7860670 Oct 27 '18 at 12:27
  • @VTT Выход за пределы это уже не описка, а жёсткий баг. А же не буду намекать на функцию std::vector::at, вдруг обидятся. – AlexGlebe Oct 27 '18 at 12:31
  • Формулировка неверная, в C++ нет динамических переменных. В Вашем примере используется переменная указатель. – JK_Action Oct 29 '18 at 11:08

1 Answers1

2

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

int *varr = new int(5);

приводит к выделению в куче одной единственной переменной типа int (не массив), и инициализации этой переменной числом 5. Таким образом, дальнейшие попытки заполнить массив по указателю varr с выходом за пределы этого одного единственного элемента приводят к неопределённому поведению. С++ не различает сырые указатели на скалярные типы от указателей, за которыми скрывается массив таких объектов.

Если хочется максимально обезопасить себя от проблем выхода за границы массива, стоит использовать хотя бы std::vector и функцию доступа к элементам at. В таком случае, обращение по невалидным индексам сгенерирует исключение, которое можно будет перехватить. Однако всё это по-прежнему будет работать только в процессе выполнения программы. Для того, чтобы найти подобные ошибки в коде как можно раньше, следует воспользоваться всевозможными программами статического анализа кода. Самые очевидные примеры, это CppCheck и Clang Static Analyzer.

αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119