Любопытное поведение std :: string :: operator [] в MSVC - PullRequest
0 голосов
/ 14 декабря 2010

Я использовал несколько полуитераторов для токенизации std :: string и столкнулся с любопытной проблемой с оператором [].При построении новой строки из позиции с использованием char * я использовал что-то вроде следующего:

t.begin = i;
t.end = i + 1;
t.contents = std::string(&arg.second[t.begin], &arg.second[t.end]);

, где arg.second - это std :: string.Но если i - это позиция последнего символа, то arg.second[t.end] сгенерирует отладочное утверждение, даже если указатель «один за другим» является хорошо определенным поведением и даже общим для примитивных массивов, а так как конструкторвызывается с использованием итераторов. Я знаю, что конечный итератор никогда не будет разыменован.Не кажется ли логичным, что arg.second[arg.second.size()] должно быть допустимым выражением, производящим эквивалент arg.second.end() в виде символа *?

Ответы [ 5 ]

4 голосов
/ 14 декабря 2010

Вы не берете указатель на один за концом, вы ДОСТУПАЕТЕ один за концом, а затем получаете адрес этого.Совершенно иное, и хотя первое хорошо определено и правильно сформировано, последнее тоже не очень.Я предлагаю использовать конструктор итераторов, который в основном используется вами, но делайте это с итераторами вместо char *.Смотрите комментарий Александра.

3 голосов
/ 14 декабря 2010

operator[](size_type pos) const не возвращается один за другим - pos == size (); он возвращает charT(), что является временным. В не const версии operator[] поведение не определено.

21.3.4 / 1

оператор const_reference [] (size_type pos) const; оператор ссылки [] (size_type pos); 1 Returns: если pos

2 голосов
/ 14 декабря 2010

Что хорошо определено, так это создание итератора один за концом. (Указатели также могут быть итераторами.) Однако, разыменование , такой итератор даст неопределенное поведение .

Теперь, что вы делаете, это подписка на массив , и это очень отличается от формирования итераторов, потому что он возвращает ссылку на объект, на который ссылаются разыменование итератор). Вам, безусловно, не разрешено получить доступ к массиву один за другим.

1 голос
/ 14 декабря 2010

std::string не является массивом.Это объект, интерфейс которого похож на массив (а именно, обеспечивает operator[]).Но на этом сходство заканчивается.

Даже если мы на секунду предположим, что std::string - это просто оболочка, построенная поверх обычного массива, то для того, чтобы получить указатель «один за другим»для сохраненной последовательности вы должны сделать что-то вроде &arg.second[0] + t.end, т. е. вместо прохождения через интерфейс std::string сначала перейдите в область обычных указателей и используйте обычную низкоуровневую арифметику указателей.

Однакодаже это предположение неверно и что-то вроде &arg.second[0] + t.end - это путь к катастрофе.std::string не гарантирует сохранение контролируемой последовательности в виде массива.Не гарантируется, что он будет храниться постоянно, а это означает, что независимо от того, куда указывают ваши указатели, вы не можете предполагать, что сможете выполнять итерацию от одного к другому, используя арифметику указателей.

Если вы хотите использоватьstd::string в некоторых устаревших интерфейсах на основе указателей у вас есть только один выбор - использовать метод std::string::c_str(), который сгенерирует непостоянную копию контролируемой последовательности на основе массива.

PS Примечание,Кстати, в оригинальных спецификациях C и C ++ запрещено использовать метод &a[N] для получения указателя «один за другим» даже для обычного встроенного массива.Вы всегда должны убедиться, что вы не используете оператор [] с индексом конца года.Легальный способ получить указатель всегда был что-то вроде a + N или &a[0] + N, но не &a[N].Последние изменения легализовали и подход &a[N], но, тем не менее, изначально он не был легальным.

0 голосов
/ 14 декабря 2010

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

Но ...

Для того, что вы пытаетесь сделать, почему бы просто не использовать конструктор basic_string( const basic_string& str, size_type index, size_type length ); для создания подстрок?

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