LINUX.ORG.RU

C++: Iterators

 ,


2

1

Имеется простая программа, цель в том, чтобы сконвертировать десятичные числа в строке в двоичные. Юнит-тесты прилагаются Вот этот кусок не работает: https://gist.github.com/pashazz/4bc845f91186f45cbbba

Если изменить его вот так: https://gist.github.com/pashazz/c3fe961bceb378806b31, то все работает.

код: https://github.com/pashazz/replacer unit-тесты прилагаются: ./runUnitTests

★★★★

Потому что

std::basic_string::replace()

Iterator validity
Any iterators, pointers and references related to this object may be invalidated.

Uter ()
Последнее исправление: Uter (всего исправлений: 1)
Ответ на: комментарий от Uter

Получается, никак нельзя реализовать это с итераторами, можно только с индексами?

pashazz ★★★★ ()
Ответ на: комментарий от pashazz

можно, но дешевле результат в новую стрингу писать

vova7890 ★★★ ()
Ответ на: комментарий от pashazz

Нет, это нельзя сделать и с индексами тоже, так как длина двоичных чисел не совпадает с длиной десятичных. только копировать в новую строку внося соответствующие изменения

Uter ()
Ответ на: комментарий от Uter

Это я уже предусмотрел в версии с индексами, корректируя i после каждого вызова replace. Но таки да

pashazz ★★★★ ()
Ответ на: комментарий от pashazz

корректируя i

Да, так наверное можно, но игра не стоит свеч

Uter ()
Ответ на: комментарий от Uter

Хорошо: сделал вот так:

void numbersToBinary(string &src) {
    string newString;
    for (string::iterator iter = src.begin(); iter != src.end(); iter++) {
        if (isdigit(*iter)) {
            string::iterator numberStart = iter++; //numberStart = iter;
            while ((iter != src.end()) && (isdigit(*iter))) {
                iter++;
            }
            string ins = decimalToBinary(string(numberStart, iter));
            newString.append(ins);
        }
        else
            newString.push_back(*iter);

    }
    src = newString;
}

а итератор внаглую перешагивает src.end(); с чем это может быть связано?

GDB:

Breakpoint 2, numbersToBinary (src="My favourite number is13and nevermind 13") at /home/pasha/projects/miem/Replacer/func.cpp:58
58                  newString.append(ins);
(gdb) print ins
$40 = "1101"
(gdb) s
51          for (string::iterator iter = src.begin(); iter != src.end(); iter++) {
(gdb) print iter
$41 = 0 '\000'
(gdb) s
__gnu_cxx::__normal_iterator<char*, std::string>::operator++ (this=0x7fffffffd7d0) at /usr/include/c++/4.9.1/bits/stl_iterator.h:757
757           { return __normal_iterator(_M_current++); }
(gdb) s
__gnu_cxx::__normal_iterator<char*, std::string>::__normal_iterator (this=0x7fffffffd780, __i=@0x7fffffffd788: 0x6a1a10 "") at /usr/include/c++/4.9.1/bits/stl_iterator.h:729
729           : _M_current(__i) { }
(gdb) s
__gnu_cxx::operator!=<char*, std::string> (__lhs=16 '\020', __rhs=0 '\000') at /usr/include/c++/4.9.1/bits/stl_iterator.h:832
832         { return __lhs.base() != __rhs.base(); }
(gdb) s
__gnu_cxx::__normal_iterator<char*, std::string>::base (this=0x7fffffffd7d0) at /usr/include/c++/4.9.1/bits/stl_iterator.h:794
794           { return _M_current; }
(gdb) s
__gnu_cxx::__normal_iterator<char*, std::string>::base (this=0x7fffffffd810) at /usr/include/c++/4.9.1/bits/stl_iterator.h:794
794           { return _M_current; }
(gdb) s
numbersToBinary (src="My favourite number is13and nevermind 13") at /home/pasha/projects/miem/Replacer/func.cpp:52
52              if (isdigit(*iter)) {
(gdb) print iter
$42 = 16 '\020'
(gdb) print src.end()
$43 = 0 '\000'
pashazz ★★★★ ()
Ответ на: комментарий от Uter

ха-ха

при этом, если добавить в конец цикла костыль:

        if ( iter == src.end())
            break;

то все работает!!!

pashazz ★★★★ ()
Ответ на: ха-ха от pashazz

работает

void numbersToBinary(string &src) {
    string newString;
    for (string::iterator iter = src.begin(); iter != src.end(); iter++) {
        if (isdigit(*iter)) {
            string::iterator numberStart = iter++; //numberStart = iter;
            while ((iter != src.end()) && (isdigit(*iter))) {
                iter++;
            }
            string ins = decimalToBinary(string(numberStart, iter));
            newString.append(ins);
            newString.push_back(*iter);
        }
        else
            newString.push_back(*iter);

        if ( iter == src.end())
            break;
    }
    src = newString;
}
pashazz ★★★★ ()

Что люди только не делают, чтобы не учить Haskell.

anonymous ()
Ответ на: комментарий от anonymous

чтобы не учить Haskell.

Ну да. Нет итераторов. нет и проблем :-)

monk ★★★★★ ()

давно хотел спросить - твои программы самоубиваются?

mos ★★☆☆☆ ()
Ответ на: работает от pashazz

Re: работает

Во-первых, зачем использовать постфиксный инкремент с итераторами?

Во-вторых, проверку выхода за конец строки надо ставить раньше - внутренний цикл while (или даже инкремент перед ним) может выйти за конец, а потом идет попытка получить значение по итератору (newString.push_back).

И, надеюсь, ты понял, откуда было перешагивание через src.end ?

moroz ()
Ответ на: Re: работает от moroz

И, надеюсь, ты понял, откуда было перешагивание через src.end ?

Я не понял, объясни если знаешь, плиз.

JANB ()
Ответ на: комментарий от JANB

Так for работает. Проверка выполняется перед телом, инкремент - после. А тут итератор еще и в теле двигается и если там он дошел до конца, то for сначала сдвинет его еще дальше и только потом проверку выполнит.

На stackoverflow по ссылке все подробно объяснили.

moroz ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.