Блог пользователя yury_chameleon

Автор yury_chameleon, 13 лет назад, По-русски

Обнаружил "ошибку времени выполнения", связанную с библиотекой . Данная ошибка возникла при выполнении моего решения задачи 154E - Martian Colony (полный код файла можно посмотреть тут: 1340125) на втором тесте при заполнении объекта класса . Вываливается одинаково при любых способах заполнения листа, например:

std::list<int> per2;
for (i = 0; i < j; i++) per2.push_back(per[i]);

или

std::list<int> per2(per, per + j);

Код ошибки — 0xc0000005 (неправильное обращение к памяти). Пробовал на всех поддерживаемых сайтом компиляторах С++ — результат один и тот же, при чем именно на втором тесте. Массив per однозначно корректно заполнен, проверял. У меня же на компьютере (работаю в Microsoft Visual C++ 6.0) никаких ошибок не возникает.

В связи с этим возникает вопрос: можно ли вообще надеяться на контейнеры STL в С++?

  • Проголосовать: нравится
  • -26
  • Проголосовать: не нравится

»
13 лет назад, # |
  Проголосовать: нравится -8 Проголосовать: не нравится

Yes, of course! but you must know where and how to use theme.

»
13 лет назад, # |
  Проголосовать: нравится -7 Проголосовать: не нравится

Откуда уверенность, что падает именно создание листа? В циклах ниже i3 указывает сразу на третий элемент листа, и дальше почти сразу сдвигается еще на один элемент вправо -- то есть решение будет работать только если а) в листе есть хотя бы черыте элемента или б) вызов оператора ++ на итератор, указывающий на end, по прежнему указывает на end. Я бы скорее поверил, что ошибка кроется в этом цикле. В любом случае, на контейнеры, вообще говоря, надеяться можно, и глупо их не использовать. Надо просто ознакомиться с тем, как они устроены, и какие у них есть подводные камни (например, что удалять из вектора итерируя по нему опасно -- хоть и возможно)

П.С.

(работаю в Microsoft Visual C++ 6.0)

Это просто без комментариев.

  • »
    »
    13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Я ради интереса запустил у себя под g++, все отработало. На сервере действительно падает даже в такой форме:

        std::cout << n << ' ' << j << ' ' << (int)per << std::endl;
        //std::list<int> per2(per, per + j);
        std::list<int> per2;
        std::cout << "before" << std::endl;
        for (int i = 0; i < j; i++)
        {
            std::cout << "inserting " << i << std::endl;
            per2.push_back(per[i]);
        }
        std::cout << "after" << std::endl;
    

    На сервере выводит

    4 4 2370944
    before
    inserting 0
    inserting 1
    

    и дохнет. Похоже где-то бьётся память, только я не втыкаю где.

    UPD: О, нашёл! Точно где-то происходит вылезание в отрицательные элементы per, потому что если сделать так:

        per = new int[2 * n];
        per += n;
    

    то всё работает. В общем, C++ такая верёвка :-) Аккуратнее с этим, побив память в начале программы, можно огрести в самом конце.

    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      В отладочном выводе видно, что j = 4, в коде видно, что перед этим происходит j--, а значит реально было заполнено пять элементов массива, заведенного на четыре. Или я не прав? :о

      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Похоже прав. В общем, код сам по себе не блещет аккуратным обращением с массивами, а тут ещё и массив заводится динамически ровно на n элементов.

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

        • »
          »
          »
          »
          »
          13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          блин, и действительно ж вылез на один элемент. спасибо =[