Форум программистов, компьютерный форум CyberForum.ru

Перезапись строки и Bad_alloc - C++

Восстановить пароль Регистрация
 
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.08.2012, 19:14     Перезапись строки и Bad_alloc #1
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
BOOL ROOM::AddHistory(const char* newHistory)
{
    BOOL newHistorySize = strlen(newHistory)+1;
    char* shiftHistory;
    if (_r_historySize+newHistorySize >= ROOM_HISTORY_SIZE)
    {
        shiftHistory = new char[ROOM_HISTORY_SIZE+1];
        int erasableHistorySize = 0, shiftPos = 0;
        do
        {
        --_r_historyNoteCount;
        erasableHistorySize += (strlen(_r_history+erasableHistorySize) + 1);
        } while (_r_historySize+newHistorySize-erasableHistorySize >= ROOM_HISTORY_SIZE);
        for (size_t noteCount=1; noteCount<=(unsigned)_r_historyNoteCount;
            ++noteCount, shiftPos+=(strlen(shiftHistory+shiftPos)+1))
        {
            strcpy_s(shiftHistory+shiftPos, ROOM_HISTORY_SIZE-shiftPos, "");
            strcpy_s(shiftHistory+shiftPos, ROOM_HISTORY_SIZE, _r_history+erasableHistorySize+shiftPos);
        }
        _r_historySize = shiftPos;
        delete _r_history;
        _r_history = shiftHistory;
    }
 
    strcpy_s(_r_history+_r_historySize, ROOM_HISTORY_SIZE-_r_historySize, "");
    strcat_s(_r_history+_r_historySize, ROOM_HISTORY_SIZE-_r_historySize, newHistory);
    _r_historySize += newHistorySize;
    ++_r_historyNoteCount;
 
    return PROCESS_SUCCESS;
}
Данный код получает сообщение, которое нужно добавить в историю. Если суммарная длина больше константы, то затираются предыдущие сообщения (да, здесь используется ещё один буфер, который можно не использовать и перезаписывать само сообщение собой же). Дело в том, что, иногда, она вызывает Bad_alloc exception, а иногда отрабатывает нормально. Константа ROOM_HISTORY_SIZE = 8182. Если её повысить до 200к и попробовать записать столько же символов, то всё нормально, а значит памяти хватает и проблема не в этом.

Я бы отписал стэк вызова функций, но после последний час я не могу получить эту ошибку снова, хотя и ничего не менял в коде.

Добавлено через 1 час 33 минуты
С чем вообще может быть связан Bad_alloc помимо того, что кончилась память? Ведь оператор new выделяет память в куче, которая ограничена физ. памятью, а значит о конце кучи при 4гб ОЗУ и выделении массива на 8кб не может и речи идти

Добавлено через 38 минут
Если повысить буфер до 28 тысяч, то выкидывает ошибку strcpy_s в строке :
strcpy_s(shiftHistory+shiftPos, ROOM_HISTORY_SIZE, _r_history+erasableHistorySize+shiftPos); - которая под номером 18. Буфер на 18 тысяч выкидывает так же на strcpy_s в этой же строчке. Буфер на 8 тысяч через раз выкидывает исключение то в этой функции, то в другой, где я выделяю буфер на 1004 элемента типа char. Последняя проблема имела бы решения (в моей понимании) при переполнении, но в сосокупности с "безошибочной работой" до 28 тысяч.. Даже и не знаю, что сказать.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.08.2012, 19:14     Перезапись строки и Bad_alloc
Посмотрите здесь:

C++ Поиск строки в файле и её перезапись
C++ bad_alloc
bad_alloc или bad_alloc() C++
C++ Bad_alloc
C++ Ошибка terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Intel~lect
 Аватар для Intel~lect
135 / 124 / 2
Регистрация: 03.07.2012
Сообщений: 355
30.08.2012, 20:17     Перезапись строки и Bad_alloc #2
Может быть сделать проверку на выделение памяти?
C++
1
2
shiftHistory = new char[ROOM_HISTORY_SIZE+1];
assert(shiftHistory != 0);
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
30.08.2012, 21:15     Перезапись строки и Bad_alloc #3
Intel~lect, new кидает исключение, а не возвращает 0.
novi4ok
549 / 502 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
30.08.2012, 21:30     Перезапись строки и Bad_alloc #4
а что эта строчка делает?
C++
1
BOOL newHistorySize = strlen(newHistory)+1;
почему не прямо
C++
1
BOOL newHistorySize = TRUE;
?
или это хитрость такая какая-то хитрая?

что должно произойти, если длина входного сообщения сразу больше выделенного буфера?

зачем ф-я возвращает значение, если оно всегда одинаковое?

объясни на пальцах, что должна эта штука делать. допустим, размер "истории" == 10. история сперва пустая. потом приходят следующие "сообщения":
aaa
bbb
ccc
ddd
eeeeeeeeeeeeeeeeee
как будет выглядеть "история" после обработки кадого из них?
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
31.08.2012, 12:22  [ТС]     Перезапись строки и Bad_alloc #5
Intel~lect, даже если делать проверку, то я все равно в минусе, ибо нужно выделить память, а послать на new в циклу while (bad_alloc) - не катит. Здесь все должно отрабатывать нормально.
Хотя может есть какой-то способ встать в ожидание памяти помимо while? Тогда было бы ясно - ошибка в кол-ве памяти или ещё в чем-то?

novi4ok, BOOL - это unsigned int в WinApi. Любая функция должна возвращать значение о корректной работе (в моей понимании). Кто знает, может я добавлю ещё чего внутрь и придется возвращать уже PROCESS_FAILED?
strlen(something)+1 - кол-во символов в строке something + ещё 1 символ для перехода на позицию ЗА \0, чтобы не затереть её.
Я не знаю, что объяснять в алгоритме, ибо, возможно, написан он "не красиво", но на самом деле все просто.

p.s В изначально _r_history хранятся строчки вида "............\0.........\0..........." - как видно, все три нуль-терминантные.
И ещё, входное сообщение никогда не больше выходного. Входное сообщение максимум 1000 символов, таким образом невозможно добиться зацикливания.

Так же пример :
Допустим, у меня сейчас ROOM_HISTORY_SIZE = 10. Макс. кол-во символов в приходящей истории 5. Вот пример.
Имеется история :
123
44
Приходит сообщение
12345 // !Overfilling!
Я прохожу по первой строчке и вычитаю прибавляю её длину к переменной erasableHistorySize (история для удаления).
Если теперь (после вычитания этой длины) длина истории пришла в норму (входит в буфер), то я перезаписываю её.
Окончательная история в этом случае :
44
12345

Замечу, что если к этому сообщению добавить ещё :
34567
то ответ будет :
34567
ибо у меня стоит проверка не на >, а на >=ROOM_HISTORY_SIZE


Добавлено через 3 часа 35 минут
up-to-date

Добавлено через 2 часа 8 минут
Похоже смог разобраться с проблемой. А она была в той самой строчке:
strcpy_s(shiftHistory+shiftPos, ROOM_HISTORY_SIZE, _r_history+erasableHistorySize+shiftPos);
Я думал, что второй параметр - макс. кол-во символов к считыванию, а значит оно не так уж и важно, но нет. Так как (первый параметр) shiftHistory имеет размер ROOM_HISTORY_SIZE, то из второго параметра нужно было вычитать shiftPos. Так уж вышло, что я интуитивно делал это во всех других strcpy_s, а тут не сделал, и вот результат. Выделение памяти с bad_alloc видимо происходило из-за того, что я выделял уже выделенную (или перезаписанную) память при размере ROOM_HISTORY_SIZE (без -shiftPos).
novi4ok
549 / 502 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
31.08.2012, 19:48     Перезапись строки и Bad_alloc #6
если уж все это обязательно в отной строчке нужно проделывать, я бы memmove использовал, или в boost что-нибудь подходящее поискал. а проще всего - std::list<std::string>. если ну устраивает в качестве "размера истории" количество строк, а нужна обязательно их суммарная длина - ну вел бы счетчик где-нибудь сколько удаляю и сколько добавляю. проще все это сделать было бы и нагляднее для понимания.
Yandex
Объявления
31.08.2012, 19:48     Перезапись строки и Bad_alloc
Ответ Создать тему
Опции темы

Текущее время: 01:24. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru