Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ тип string, утечка памяти

Автор: TarasBer 18.09.2009 19:35

Работу с типом char* я тупо не смог осилить, так как так и не понял, при каких операциях надо выделять ему память, при каких не надо. Короче ужаснейший тип, и кто его придумал, и ну его нафиг.
Решил применить string - я так понял, что это аналог паскалевского. Но обнаружилось, что после динамического создания структуры, содержащей поле типа string, и её удаления кол-во занимаемой памяти меняется. Встатив этот кусок в бесконечный цикл, я обнаружил, что память, пожираемая программой, пульсирует от 10 до 50 MЬ.
Вторая проблема - при отладке на операциях с этим типом он лезет в свои модули, мне они неинтересны, как запретить отладчику в них влазить.
Блин, настроек по сравнению с Дельфой раза в 3 больше, на кой.

Автор: volvo 18.09.2009 20:49

Цитата
так и не понял, при каких операциях надо выделять ему память, при каких не надо.
Выделять память надо всегда. Просто когда-то ее можно выделить самим фактом инициализации строки:
char *s = "my string";
, а иногда это приходится делать через new, то есть выделять память динамически.

Цитата
после динамического создания структуры, содержащей поле типа string, и её удаления кол-во занимаемой памяти меняется.
Можно посмотреть на структуру, и на то, как выделяется память? Что говорят средства отладки (скажем, тот же CodeGuard)?

Добавлено через 1 мин.
Цитата
Вторая проблема - при отладке на операциях с этим типом он лезет в свои модули, мне они неинтересны, как запретить отладчику в них влазить.
Не делать "Step Into", а пользоваться вместо этого "Step Over", тогда отладчик будет выполнять всю строку, а не по отдельным операциям.

Автор: TarasBer 18.09.2009 21:45

Цитата(volvo @ 18.09.2009 17:49) *

Выделять память надо всегда. Просто когда-то ее можно выделить самим фактом инициализации строки:
char *s = "my string";
, а иногда это приходится делать через new, то есть выделять память динамически.


Но просто s = "my string" уже не катит. Что делают с памятью strcpy и strcat - тоже непонятно.

Цитата


Можно посмотреть на структуру, и на то, как выделяется память? Что говорят средства отладки (скажем, тот же CodeGuard)?



Ну например:
Код

struct S {
    string Name;        
};
...
S *s;
while(1){
    s = new S[8];
    delete s;
};

Прикол в том, что если заменить string на int, то утечка полностью исчезает.

В кодгуарде пока не разобрался.

Цитата



Добавлено через 1 мин.
Не делать "Step Into", а пользоваться вместо этого "Step Over", тогда отладчик будет выполнять всю строку, а не по отдельным операциям.

А если строка передаётся как параметр в функцию? Тогда степ овер пропусткает то, что делает функция, а это как раз не надо. А степ инто тут же залезает в дебри всякие.

Автор: volvo 18.09.2009 22:23

Цитата
Но просто s = "my string" уже не катит.
Естественно... Для работы со строками в стиле С существуют функции, начинающиеся на str... В данном случае тебе нужен strcpy.

Цитата
Что делают с памятью strcpy и strcat - тоже непонятно.
С чего бы? Ничего они не делают с памятью. В описании strcpy ясно написано, что "для того, чтобы избежать порчи памяти из-за переполнения, указатель destination должен указывать на область памяти достаточного объема". То есть, выделить необходимую память перед копированием - забота программиста.

То же самое касается и strcat, destination должен указывать на область памяти достаточного объема, чтобы вместить результирующую строку и завершающий символ '\0'.

Цитата
Прикол в том, что если заменить string на int, то утечка полностью исчезает.
Нет, прикол не в этом. А в том, что если ты выделяешь память под МАССИВ структур, то и удалять надо МАССИВ структур:
struct S {
string Name;
};
...
S *s;
while(1){
s = new S[8];
delete [] s;
} // здесь точка с запятой не нужна, кстати

А почему утечка исчезает при замене string на int - это отдельный разговор, сли интересно - я расскажу, а просто так не хочется по клавишам стучать.

Автор: TarasBer 18.09.2009 22:43

Цитата(volvo @ 18.09.2009 19:23) *

С чего бы? Ничего они не делают с памятью. В описании strcpy ямсно написано, что "для того, чтобы избежать порчи памяти из-за переполнения, указатель destination должен указывать на область памяти достаточного объема". То есть, выделить необхпдимую память перед копированием - забота программиста.


И ВСЕ стандрртные функции, возвращающие char* - тоже требуют предварительного выделения памяти? Ладно, тогда вроде понятнее. Попробую эти char* ещё раз расписать. А то что все пишут на C и не жалуются, а я не всё не врубаюсь, всё время кажется, что меня Паскаль испортил.

Цитата

Нет, прикол не в этом. А в том, что если ты выделяешь память под МАССИВ структур, то и удалять надо МАССИВ структур:
Код

...
  delete [] s;
} // здесь точка с запятой не нужна, кстати


Вот ведь оно как, так и знал, что какую-то закорючку забыл поставить.
А лишние точки с запятой, не вызывающие ошибок компиляции - разве вредят?
Цитата

А почему утечка исчезает при замене string на int - это отдельный разговор, сли интересно - я расскажу, а просто так не хочется по клавишам стучать.

Интересно.

Хотя не, такой момент ещё непонятен. Если у формы есть свойство Caption, то надо писать Caption = IntToStr(i) или сначала S = IntToStr(i), а потом Caption = S, где S - промежуточная строка, под которую выделена память?

Автор: volvo 18.09.2009 23:05

Цитата
А лишние точки с запятой, не вызывающие ошибок компиляции - разве вредят?
До поры до времени - не вредят... Пока ты не напишешь какую-нибудь конструкцию, в которой эта самая точка с запятой, скажем, образует пустой цикл, пустую ветку if/else или еще что-нибудь такое же трудноуловимое. Синтаксис С очень многое позволяет "намудрить", поэтому лучше избавляться от привычки ставить лишние символы, даже если они не вызывают ошибок компиляции.

Цитата
Интересно.
Ну, тогда смотри: при выполнении delete, если добавить [], как я сделал, происходит вот что: сначала для каждого элемента массива вызывается его деструктор, и только потом освобождается память, выделенная под сам массив. Что происходит в случае замены string на int? А ничего страшного не произойдет, даже если не вызвать деструктор для int, от него все равно толку нет, утечки не будет даже без его вызова. В случае string все серьезнее: это полноправный класс, который имеет конструктор, выделяющий память. И экземпляр этого класса требуется удалить, иначе сам экземпляр остается висеть в памяти, а указатель на него потеряется.

Поэтому всегда, когда выделяешь память динамически под массив, либо состоящий из не POD-типов (Plain Old Data, данные в стиле С), либо содержащий такие типы (как у тебя - структура, которая содержит non-POD type), то освобождай ее всегда с использованием delete [] p_arr;, чтобы быть уверенным в том, что для каждого элемента вызовется деструктор, и только потом удалится сам массив.

Автор: TarasBer 19.09.2009 0:05

Цитата(volvo @ 18.09.2009 20:05) *


Ну, тогда смотри: при выполнении delete, если добавить [], как я сделал, происходит вот что: сначала для каждого элемента массива вызывается его деструктор, и только потом освобождается память


Это, я так понял, только для не-POD типов, потому что для массива объектов для каждого элемента деструктор надо вызывать руками?
Решил вместо char* работать с AnsiString, а то у всех компонентов свойства как раз такого типа.

Автор: volvo 19.09.2009 0:53

Цитата
Это, я так понял, только для не-POD типов, потому что для массива объектов для каждого элемента деструктор надо вызывать руками?
Угу, именно поэтому...

Кстати, а что за задачу ты решаешь? Может, будет выгоднее не выделять самому динамически память под массив, а воспользоваться либо vector<AnsiString> либо vector<S>? Тут ведь мало того, что не надо выделять память вручную, так еще и удалять вектор не надо, он описывается статически, следовательно при выходе из области видимости самоликвидируется (причем корректно, перед этим вызвав деструктор каждого своего элемента).

Автор: TarasBer 19.09.2009 1:07

Цитата(volvo @ 18.09.2009 21:53) *

Кстати, а что за задачу ты решаешь?


Я решаю задачу освоения нового для меня и довольно хитрого языка, за который к тому же много где платят, в отличие от Дельфей (увы, реальность примерно такова). Пока впечатление отвратительное.
На примере калькулятора со встроенным парсером и ещё некоторыми наворотами (он уже знает, что 2+2*2 равно 6). Тем более, что опыт распознавания выражений имею.
Собсна та структура, содержащая строчку - это описание функций, содержащее как раз и имя, и ссылку на операцию, и ещё много чего.

Цитата

Может, будет выгоднее не выделять самому динамически память под массив, а воспользоваться либо vector<AnsiString> либо vector<S>? Тут ведь мало того, что не надо выделять память вручную, так еще и удалять вектор не надо, он описывается статически, следовательно при выходе из области видимости самоликвидируется (причем корректно, перед этим вызвав деструктор каждого своего элемента).


Ну я так понял, что фишка С++ в полной открытости всех действий перед программистом. И мне кажется, что использовать в нём подобные вещи - всё равно что покупать джип для езды по городу.

Автор: volvo 19.09.2009 1:29

Фишка С++ - не в том, чтобы не писать свой велосипед каждый раз, да еще и чинить его потом на каждом повороте, а в том, что ты берешь отлаженную сотнями и тысячами программистов библиотеку (я про STL) и просто реализуешь свою задачу. Нет, дело твое, конечно, но потом не говори, что написание программ на С++ занимает ОЧЕНЬ долгое время. Оно занимает просто долгое время, а не ОЧЕНЬ. ОЧЕНЬ - это из-за того, что ты опять с нуля реализуешь то, что уже есть в языке (хотелось бы напомнить, что STL - это часть Стандарта C++).

По поводу "джипов". Лучше я буду ездить везде на джипе, чем каждый раз менять транспортные средства (доехал до перекрестка, а там - лужа. Упс... Надо пересесть в амфибию, а то на велосипеде и утонуть можно). Хотя ко мне это относится меньше всего. Ада - язык универсальный, причем с Паскалевским синтаксисом, что снимает огромную часть проблем, да и оплачивается программирование на нем в разы (если не на порядки) выше, чем программирование на С++. И средств, подобных тому же STL-ю там не меньше, а даже больше... Так что я свой джип уже нашел. Передвигается одинаково уверенно и по Win, и по Lin, и по Embedded, и вообще практически по любым существующим территориям. Хочешь попробовать догнать? Но это уже оффтоп в данной теме.

Автор: TarasBer 19.09.2009 2:44

Цитата(volvo @ 18.09.2009 22:29) *

Фишка С++ - не в том, чтобы не писать свой велосипед каждый раз, да еще и чинить его потом на каждом повороте, а в том, что ты берешь отлаженную сотнями и тысячами программистов библиотеку (я про STL) и просто реализуешь свою задачу.


Вот как раз для такого куда лучше бы подошёл какой-нибудь другой язык, пусть не с таким оптимизированным кодом, как говорят про C++, зато более дружелюбный к программисту. А иначе зачем вообще этот C++ нужен?

Автор: renesko1 19.09.2009 18:29

С++ наоборот ИМХО понятен, если программа написана с высоким и правильным содержанием STL
компонентов.(к сожалению, мои программы этим пока не очень отличаются).
std::vector<car> вектор из машин)

Автор: TarasBer 19.09.2009 22:55

Хьюстон, у нас опять проблемы.
При вводе корректных выражений утечка прекратилась, но при вводе "1/0" память опять потекла. Само деление обёрнуто в


try {
}
catch (...) {
};



Внутри трая само деление, внутри катча присвоение пустого значения.

Автор: volvo 19.09.2009 23:34

Где память выделяется, и где она освобождается? Если сделать так:

	S *s = new S[8];
try
{
//
int i = 1, j = 0;
int x = i / j;
}
catch(...)
{
// Ну, по-хорошему, тут надо еще уточнить что за исключение
ShowMessage("Division by Zero");
}
delete [] s;
, то утечки не будет... Покажи, как делаешь ты...

Автор: TarasBer 20.09.2009 0:00

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


TComplex operator / (TComplex X, TComplex Y) {
TComplex Z;
try {
if (X.IsValue && Y.IsValue) {
Z.IsValue = true;
long double D = 1 / (Y.Re * Y.Re + Y.Im * Y.Im);
Z.Re = D * (X.Re * Y.Re + X.Im * Y.Im);
Z.Im = D * (-X.Re * Y.Im + X.Im * Y.Re);
} else {
Z.IsValue = false;
};
} catch (...) {
Z.IsValue = false;
};
return Z;
};


Автор: volvo 20.09.2009 1:03

Ну, хорошо... Это переопределение операции деления. Для того, чтобы у тебя была утечка, надо, чтобы память выделялась и не освобождалась, так? Вот я и хочу увидеть, как ты вызываешь эту самую операцию деления, и что происходит в ее ближайшем окружении, после чего у тебя теряется память...

Исключение поймано, IsValue результата установлено в false, все нормально. Дальше все зависит от того, как именно ты обрабатываешь этот IsValue...

Автор: TarasBer 20.09.2009 1:23

Значит собсна вычисление выражения выглядит так:


void TTree::GetValue() {
if (Data.Func) {
for (int i = 0; i < Count; i++) {
Child[i]->GetValue();
};
Data.Value = Data.Func->Operation(Count, Child);
};
};


Тут пока так сделано, что если указатель Data.Func нулевой, то значит эта вершина содержит константу и содержимое Value и так уже правильное. Сам Data.Func, если не нулевой, ссылается на элемент из заранее созданного массива, то есть его создавать и удалять не надо.
Счётчик объектов TTree говорит, что после все действий объектов ноль - то есть тут тоже всё в порядке.
Operation - это указатель на тип-функцию:


typedef TComplex(TTreeFunc)(int Count, TTree **Args);

struct TFunc {
...
TTreeFunc *Operation;
};



Собсно сама операция, которая тут вызывается:


TComplex Div(int Count, TTree **Args) {
TComplex Result;
if (Count != 2) {
Result.IsValue = false;
} else {
Result = Args[0]->Data.Value / Args[1]->Data.Value;
};
return Result;
};



Тоже ничего не создаётся.

Автор: volvo 20.09.2009 3:02

Цитата
Счётчик объектов TTree говорит, что после все действий объектов ноль - то есть тут тоже всё в порядке.
Сомневаюсь... Поскольку сведения у меня о твоей программе только частичные - попробовал сделать так:
TComplex Div(int Count, TComplex *Args) {
TComplex Result;
if (Count != 2) {
Result.IsValue = false;
} else {
Result = Args[0] / Args[1];
};
return Result;
};

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TComplex *f = new TComplex[2];

TComplex c = Div(2, f);
delete [] f;

ShowMessage(BoolToStr(c.IsValue, true));
}
Все нормально, утечек нет... Значит проблема-таки с TTree где-то. Подключи уже CodeGuard (у меня в Builder 2009 для этого надо установить Project -> Options -> C++ Compiler Debugging -> Enable CodeGuard в True, как это делается в BCB 6 - не помню), и посмотри, что он тебе говорит, где именно утечка?

Автор: TarasBer 20.09.2009 4:04

Запуск с гуардом даёт аксесс виолейшн, программа намертво виснет, не желает завершаться по команде из среды, завершается только проводником, причём так как среда об этом не узнаёт, для перекомпиляции приходится перезапускать среду.
Я не пойму, что за такая проблема с TTree может быть, которая с 1/1 не вылезает, а с 1/0 вылезает.

Автор: volvo 20.09.2009 4:10

Присоедини свой проект, я его прогоню в 2009... Можно в приват, если не хочешь выкладывать в общий доступ.

Автор: TarasBer 20.09.2009 4:34

Заодно я проверил, что дело не в "пустом" значении - я вставил в процедуру деления простой возврат "пустого" значения, без трая. Утечка исчезла.

> Присоедини свой проект, я его прогоню в 2009... Можно в приват, если не хочешь выкладывать в общий доступ.

Да там нечего скрывать: я пока не настолько крут, чтобы мой код имело смысл скрывать от чужих глаз.


Прикрепленные файлы
Прикрепленный файл  Calc.rar ( 494.48 килобайт ) Кол-во скачиваний: 160

Автор: volvo 20.09.2009 5:21

А ты знаешь, у меня не вылетает. У тебя вечный цикл while(1). Насколько я понимаю, ты его сделал только, чтобы проверить на утечки? Так вот по 10 минут работало без перерыва, ни одного байта памяти не прибавило... Вводил выражения 1/1 и 1/0... И в том и в другом случае прекрасно считает и результат пишется в Caption формы. В случае деления на 0 - как ты и требовал от функции она возвращает "?".

Автор: TarasBer 20.09.2009 16:10

> Так вот по 10 минут работало без перерыва, ни одного байта памяти не прибавило...

Странно. Я этот момент проверяю при помощи виндовского Task Managera, или это неправильный метод?

У меня настолько палёный билдер? Я его с какой-то шары скачал, если честно.

> В случае деления на 0 - как ты и требовал от функции она возвращает "?".

Да.

Автор: TarasBer 20.09.2009 18:07

И надо сказать, что хавает от не спеша, где-то полметра в секунду.


Эскизы прикрепленных изображений
Прикрепленное изображение

Автор: volvo 20.09.2009 18:52

Ну не получается у меня, чтоб пожиралась память... Как только установилось определенное количество памяти (после нескольких первых итераций), так и стоит как вкопанное. Если что - можешь посмотреть видео: http://vlady.uzelok.net/video/calc.avi

За 30 секунд ничего не изменилось... Что-то у тебя с Билдером... Хотя, может быть это в BDS2009 получше работа с памятью, пускай кто-нибудь еще на BCB6 проверит...

Автор: TarasBer 20.09.2009 19:07

А что это он сразу 8 метров отхватил? У меня в корректных случаях никогда до 5 не доходит. Или это уже особенности более позднего компилятора?

Автор: volvo 20.09.2009 19:15

Это Дебаг-версия + CodeGuard... Если скомпилировать в Release и отключить все, что не надо - будет гораздо меньше.

Автор: TarasBer 20.09.2009 22:20

Я правильно понимаю, что команда new для создания строки не может вызывать access violation в нормально работающей среде? А то у меня чем дальше, тем круче.

Автор: TarasBer 23.09.2009 2:17

Мне удалось подключить CodeGuard.
Запустил, ввёл 1/0. Открыл лог, который переименован в тхт и прилагается.
Если я правильно его понял, то
5 вызовов malloc
5 вызовов free
(я решил по старинке писать).
Наборы адресов совпадают.
Ставлю бесконечный цикл, запускаю, диспетчер видит утечку.
Я сойду с ума.


Прикрепленные файлы
Прикрепленный файл  Calc.txt ( 6.58 килобайт ) Кол-во скачиваний: 241

Автор: TarasBer 23.09.2009 17:12

Решил упростить свой случай до предела.
Написал в обработчике нажатия кнопки вот это:


while (1) {
int *i;
int *j;
i = (int*)malloc(sizeof(int));
j = (int*)malloc(sizeof(int));
*i = 1;
*j = 0;
int k;
try {
k = *i / *j;
} catch (...) {
k = 0;
};
free(i);
free(j);
};


Утечка есть, причём неслабая.
Может быть, дело в том, что создаётся объект-исключение, который надо как-то определять и удалять? И как это делать?

Автор: volvo 23.09.2009 17:57

Цитата
Может быть, дело в том, что создаётся объект-исключение, который надо как-то определять и удалять?
Ничего там не создается... Проверил и Билдером, и GCC - нет утечки. Что-то у тебя с Билдером явно не то. К сожалению, запустить тот EXE-шник, что ты присоединял в 21-ом посте, и проверить, дает ли он утечку, я не могу, он требует библиотеки от BCB6, а у меня их нет.

Автор: TarasBer 23.09.2009 18:16

Тогда ещё вопрос - как надо компилировать программу, чтобы она запускалась на любом компе, где есть винда?

Автор: volvo 23.09.2009 18:20

http://forum.pascal.net.ru/index.php?s=&showtopic=11325&view=findpost&p=70883

Автор: TarasBer 23.09.2009 18:26

Понятно.
Альтернативный вариант - чистое API?

Екзешник с утечкой ещё интересен?



Прикрепленные файлы
Прикрепленный файл  Calc.rar ( 747.99 килобайт ) Кол-во скачиваний: 143

Автор: volvo 23.09.2009 18:44

Цитата
Альтернативный вариант - чистое API?
И в этом случае возможны проблемы (при отсутствии Билдера в системе), какие-то библиотеки все равно привяжутся к проекту. Полностью работоспособно только приведенное по ссылке решение.

Цитата
Екзешник с утечкой ещё интересен?
Собственно, интересно было посмотреть, насколько утекает память. Да, за 12 секунд сожрало почти 30 Мб - это много. Попробуй все-таки другой Билдер, скорее всего проблема в этом, ибо я тестировал твой проект (без изменений) и на 2007 и на 2009. Ни там ни там нет утечек.

Автор: TarasBer 24.09.2009 0:31

А просканировать как-нибудь тот екзешник, чтоб понять, где глюк, ну и сравнить побайтно с результатом компилирования в ВС2009 - реально?

Автор: volvo 24.09.2009 1:52

Реально, только сравнивать надо не EXE-шники, а MAP-файлы (заставить Билдер генерировать MAP-файлы: фактически - ассемблерный код, и сравнивать результаты этой операции для обоих версий Билдера). Только это - чуть позже, у меня еще ремонт в квартире продолжается, я выхожу то с одного компьютера, то с другого, а все, что нужно для подобных детальных сравнений у меня установлено только в одном месте, я туда еще не добрался, комната завалена полностью. На следующей неделе, надеюсь, начну разгребать этот бардак, тогда уже и посмотрю, в чем разница...

Автор: TarasBer 25.09.2009 2:22

А существует ли какой-либо механизм предсказания ошибки вычислений, помимо исключения?
То есть чтобы я, зная два числа, смог заранее, без исключения, сказать, поделится (умножится, сложится, вычтется) ли одно на другое, или нет?

Автор: TarasBer 27.09.2009 17:30

Попытался заняться дальнейшим упрощением "неверного" кода.


void __fastcall TForm1::Button1Click(TObject *Sender)
{
int i = 1;
while(1) {
try {
int j = i / 0;
} catch (...) {
};
};
}


Утечка в коде, не содержащем НИ ОДНОГО указателя!
Писать сразу 1 / 0 не получится, компилятор палит.
Да, я уже скачал отдельно компилятор с другого места.

Автор: volvo 27.09.2009 17:47

Цитата
Утечка в коде, не содержащем НИ ОДНОГО указателя!
Значит, в BCB6 такая "хорошая" работа с памятью... Проверь на более новом Билдере. Попробуй проверить на другом С++ компиляторе, есть ли утечка там? Я проверил только что в BDS2009 - результат аналогичен тому, что было выше - сначала плюс несколько килобайт, а потом - без увеличения.

Автор: TarasBer 27.09.2009 18:02

Цитата(volvo @ 27.09.2009 14:47) *

Значит, в BCB6 такая "хорошая" работа с памятью...

О да, я крут, сел осваивать новый язык и тут же нашёл нехилый баг в компиляторе.
Цитата

Проверь на более новом Билдере. Попробуй проверить на другом С++ компиляторе, есть ли утечка там?

Я попробую найти другой С++ компилятор, но это не так просто.

Автор: volvo 27.09.2009 18:09

Цитата
но это не так просто.
Чего сложного?
http://www.codeblocks.org/downloads/5 (IDE вместе с компилятором и отладчиком, около 20Мб)

Автор: volvo 27.09.2009 18:40

Цитата
сел осваивать новый язык и тут же нашёл нехилый баг в компиляторе.
Нет, этот баг нашел не ты, его нашли другие... Ты просто на него нарвался. На delphigroups.info проскакивала информация об ошибке, связанной с синтаксисом catch(...) на старых Билдерах, и о том, что желательно использовать конструкцию catch(Exception&) вместо нее... Так что сначала попробуй код:
#include <exception>
// ...
int i = 1;
while(1)
{
try
{
int j = i / 0;
}
catch (Exception& e)
{
// ShowMessage(e.Message);
}

}
, и проверь, "утекает" ли по-прежнему память?

Автор: TarasBer 28.09.2009 17:20


catch (Exception &E) {
...
delete &E;
};


Помогло. Без делита - утечка.
Мдааа.

Автор: TarasBer 28.09.2009 19:47

А такой код, с удалением исключения, будет работать на новых билдерах?

Автор: volvo 28.09.2009 23:01

Цитата
А такой код, с удалением исключения, будет работать на новых билдерах?
Нет, при попытке сделать
delete &E;
получишь Invalid pointer operation, и этим дело закончится.

Автор: TarasBer 28.09.2009 23:23

Тогда какой #ифдеф на этот случай посоветуете? Я в них ноль, так как не приходилось сталкиваться с таким.

Автор: volvo 29.09.2009 1:21

Насколько я помню номера компиляторов - так:

		catch (Exception& e)
{
// ...
#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564)
delete &e;
#endif
// e.Free();
}

0x560 - это "чистый" BCB6, и еще 4 - с разными Service Pack-ами

Автор: TarasBer 29.09.2009 13:35

> && (__BORLANDC__ >= 0x560)

Ну, во-первых, у меня вроде 5.5, во-вторых, это условие говорит, что для более ранних версий этого бага не было?

Автор: volvo 29.09.2009 14:04

Ты спрашивал, как определить Билдер 6 директивами компиляции? Я тебе показал, как это делается... Нужно включить ВСЕ глючные версии - убирай нижнее условие, оставляй только верхнюю границу...

Баг был на всех Билдерах, как минимум до BDS 2006, если не до BDS 2007, только потом был исправлен. А если у тебя 5.5, то посмотри внимательно на название темы, и пойми, что телепаты обходят этот форум стороной.

Автор: TarasBer 29.09.2009 17:45

Всё, больше вопросов нет, спасибо.

Автор: TarasBer 29.09.2009 19:29

Как заставить встроенные функции модуля math не выводить ошибку в случае исключения? Если исключения ловлю Я, то зачем их ловилку всунули в модуль?!

Автор: TarasBer 30.09.2009 0:28

Заменил матх на фастматх, обнаружил новый прикол.
gcvt виснет, если ему подсунуть exp(999) в консольном приложении.
Сколько ещё багов встроено в этот замечательный компилятор?