Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Утечка памяти при работе с std::deque в C++Builder6

5.3K
07 октября 2010 года
!Волк
95 / / 19.07.2006
На днях наткнулся на баг при работе с std::deque. Следующий пример вызывает утечку памяти в C++Builder6 (Update4) .
 
Код:
std::deque<int> d(100);
  while (true) {
    // Удаляем один элемент из начала
    d.erase(d.begin(), d.begin() + 1);
    // Добавляем один элемент в конец
    d.push_back(0);
  }

Проблема возникает при использовании метода erase, принимающего два итератора. Если его заменить на erase, принимающий один итератор или на pop_front, то работает нормально.
Проверял также на C++Builder2006 и С++Builder2010, там этой проблемы нет.
11
07 октября 2010 года
oxotnik333
2.9K / / 03.08.2007
http://forum.codenet.ru/showthread.php?t=63035
баг походу в 6-ке
1
08 октября 2010 года
kot_
7.3K / / 20.01.2000
Опишите пожалуйста подробней - что вы имеете ввиду.
5.3K
09 октября 2010 года
!Волк
95 / / 19.07.2006
Цитата: kot_
Опишите пожалуйста подробней - что вы имеете ввиду.


Мне подробнее описать суть бага или это вопрос к oxotnik333?

1
09 октября 2010 года
kot_
7.3K / / 20.01.2000
Цитата: !Волк
Мне подробнее описать суть бага или это вопрос к oxotnik333?


млять. Ну а ты как сам думаешь? Если я пожелаю задать вопрос участникам дискуссии - то поверь - сумею дать понять, к кому я обращаюсь.
Вопрос без конкретных 2(to) - относится к топикстартеру. С требованием описать проблему более четко. erase - к сведению - память не освобождает, а упомянутая конструкция относится к серии - "За какой код киборга засылают в прошлое - или принудительный аборт, как благо для популяции".
Порядок вычисления в функции - произволен - и на что будет указывать итератор - один Бог знает

5.3K
10 октября 2010 года
!Волк
95 / / 19.07.2006
Хорошо, попробую подробнее, на более реальном примере.
Основное преимущество deque от vector в том, что в deque можно вставлять/удалять элементы за фиксированное время не только в конец, но и в начало. Из этих преимуществ очевидно, что удобно использовать deque например для организации последовательной обработки данных, пришедших от клиента на сервер. Предположим, случилось так, что сервер в каждом цикле получает от клиента 100 байт, вставляет их в буфер и обрабатывает только 20 байт. То есть буфер почти всегда полностью заполнен.
Код:
std::deque<char> buffer;
  const size_t buffer_max_size = 1000;
  // Цикл получения и обработки данных, приходящих от клиента
  while (true) {

    // Здесь получаем данные от клиента и вставляем их в конец буфера,
    // если в буфере свободно место для 100 байт
    if ((buffer.size() + 100) <= buffer_max_size) {
      // Имитация получения даннх от клиента: вставка в конец 100 байт
      // со значением 0
      buffer.insert(buffer.end(), 100, 0);
    }
   
    // Здесь обрабатываем первые 20 байт данных
    // ...
    // Удаляем обработанные первые 20 байт
    std::deque<char>::iterator range_begin_it = buffer.begin();
    std::deque<char>::iterator range_end_it = buffer.begin();
    std::advance(range_end_it, 20);
    buffer.erase(range_begin_it, range_end_it);
   
  }

Подобный код, если не считать некоторых упрощений, я использую в одной из своих программ. И этот код вызывает утечку памяти. Насколько я понимаю, основной вопрос только в том, баг это или неправильное использование deque. По поводу операций erase и insert в стандарте C++ 98 и 03 я не нашел, где бы явно говорилось, что в результате их применения реальный размер не должен превышать логическо (возвращаемого функцией size()) в n раз. По поводу этих операций сказано лишь, что если элементы удаляются или вставляются в конец или начало, то ссылки на оставшиеся элементы должны оставаться действительными. Из этого следует, что перераспределения памяти происходить не должно. Я не копался в исходниках билдера, но насколько мне известно, deque могут реализовывать как массив массивов. То есть при вставке элемента в конец, если в последнем массиве нет для него места, выделяется новый массив. При вставке в начало тоже самое. Такая реализация позволяет выполнить вышеперечисленные требования стандарта. И я не вижу препятствий, чтобы такая реализация не приводила к постоянному съеданию памяти.
Функция erase не освобождает память, чтобы потом туда можно было опять что то вставить. У vector-a так же. Однако, если мы заменим в коде deque на vector, утечки не будет.
Добавлю, что баг проявляется только если удалять данные частями из начала. Если поменять местами вставку и удаление, то есть вставлять в начало, а удалять из конца или же полностью удалять все элементы за один раз, баг не наблюдается.
Цитата: kot_

Порядок вычисления в функции - произволен - и на что будет указывать итератор - один Бог знает


Если я правильно понял, имеется ввиду порядок вычисления в аргументах функции? Но в этих аргументах нет вызова модифицирующих членов, поэтому порядок неважен. Тем не менее я вынес вычисление итератора конца диапазона, и заменил его на более универсальную функцию advance.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог