Ссылка на недопустимые области памяти с помощью итераторов C ++ - PullRequest
3 голосов
/ 02 апреля 2010

Я большой поклонник GCC, но недавно я заметил смутную аномалию. Используя __gnu_cxx :: __ normal_iterator (т. Е. Наиболее распространенный тип итератора, используемый в libstdc ++, C ++ STL), можно ссылаться на произвольную ячейку памяти и даже изменять ее значение без исключения! Это ожидаемое поведение? Если так, то не лазейка в безопасности?

Вот пример:

#include <iostream>
using namespace std;

int main() {
        basic_string<char> str("Hello world!");
        basic_string<char>::iterator iter = str.end();



        iter += str.capacity() + 99999;
        *iter = 'x';

        cout << "Value: " << *iter << endl;
}

Ответы [ 4 ]

6 голосов
/ 02 апреля 2010

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

Обратите внимание, что это вопрос компромисса, хорошо, когда итераторы проверяют правильность разработки, но это добавляет дополнительные операции к коду. В MSVS по умолчанию проверяются итераторы (они проверят, что они действительны и работают с ошибками при неправильном использовании =. Но это также влияет на производительность во время выполнения.

Решение, которое предоставляет Dinkumware (STL внутри VS) (проверено по умолчанию, может быть отключено с помощью параметров компилятора), на самом деле является хорошим выбором, пользователь выбирает, хочет ли он медленных безопасных итераторов или быстрых небезопасных версий. Но с точки зрения языка оба действительны.

2 голосов
/ 02 апреля 2010

Нет, это не проблема. Имейте в виду, что типичное использование итератора:

for ( type::const_iterator it = obj.begin(); it != obj.end(); ++it ){
    // Refer to element using (*it)
}

Для правильного использования итератора требуется проверка на соответствие итератору end(). С итераторами произвольного доступа, такими как тот, который вы используете, вы также можете использовать <и> с итераторами против end(). C и C ++ обычно не выполняют проверку границ, как в Java, и это ваше место, чтобы убедиться, что вы делаете это.

1 голос
/ 02 апреля 2010

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

if (iter < str.begin() || iter >= str.end())
    throw something;
0 голосов
/ 02 апреля 2010

Тебе повезло. Или не повезло. Используя ваш точный пример, я сегрегировал.

$ ./a.exe
  11754 [main] a 4992 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack)
Segmentation fault (core dumped)

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

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