Утечка памяти при работе с std::deque в C++Builder6
while (true) {
// Удаляем один элемент из начала
d.erase(d.begin(), d.begin() + 1);
// Добавляем один элемент в конец
d.push_back(0);
}
Проблема возникает при использовании метода erase, принимающего два итератора. Если его заменить на erase, принимающий один итератор или на pop_front, то работает нормально.
Проверял также на C++Builder2006 и С++Builder2010, там этой проблемы нет.
баг походу в 6-ке
Мне подробнее описать суть бага или это вопрос к oxotnik333?
млять. Ну а ты как сам думаешь? Если я пожелаю задать вопрос участникам дискуссии - то поверь - сумею дать понять, к кому я обращаюсь.
Вопрос без конкретных 2(to) - относится к топикстартеру. С требованием описать проблему более четко. erase - к сведению - память не освобождает, а упомянутая конструкция относится к серии - "За какой код киборга засылают в прошлое - или принудительный аборт, как благо для популяции".
Порядок вычисления в функции - произволен - и на что будет указывать итератор - один Бог знает
Основное преимущество deque от vector в том, что в deque можно вставлять/удалять элементы за фиксированное время не только в конец, но и в начало. Из этих преимуществ очевидно, что удобно использовать deque например для организации последовательной обработки данных, пришедших от клиента на сервер. Предположим, случилось так, что сервер в каждом цикле получает от клиента 100 байт, вставляет их в буфер и обрабатывает только 20 байт. То есть буфер почти всегда полностью заполнен.
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, утечки не будет.
Добавлю, что баг проявляется только если удалять данные частями из начала. Если поменять местами вставку и удаление, то есть вставлять в начало, а удалять из конца или же полностью удалять все элементы за один раз, баг не наблюдается.
Порядок вычисления в функции - произволен - и на что будет указывать итератор - один Бог знает
Если я правильно понял, имеется ввиду порядок вычисления в аргументах функции? Но в этих аргументах нет вызова модифицирующих членов, поэтому порядок неважен. Тем не менее я вынес вычисление итератора конца диапазона, и заменил его на более универсальную функцию advance.