Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 4 541

/ вопрос открыт /

Доброго времени суток, уважаемые эксперты!
Писал программку которая отображает битые ссылки в реестре.
Но через некоторое время работы программы возникает ошибка -переполнение стека.Долго искал в интернете - ничего.Тем более мне нужна привязка к коду.
Прилагаю скрин

К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)

Приложение:
  1. procedure TRegistrySeach.Scan(Key: String);
  2. var
  3. Str: TStringList;
  4. I: LongInt;
  5. begin
  6. if Reg.OpenKeyReadOnly(Key) then
  7. try
  8. Str := TStringList.Create;
  9. try
  10.  
  11.  
  12.  
  13.  
  14. begin
  15. Application.ProcessMessages;
  16. if stop=1 then Break;
  17.  
  18.  
  19.  
  20.  
  21.  
  22. if Reg.GetDataType(Str.Strings[I]) in [rdString, rdExpandString] then
  23. ValidData(Key, Str.Strings[I], Reg.ReadString(Str.Strings[I]));
  24. end;
  25.  
  26.  
  27.  
  28. Reg.GetKeyNames(Str);
  29. for I := 0 to Str.Count - 1 do
  30. begin
  31. Application.ProcessMessages;
  32. if stop=1 then Break;
  33.  
  34. if Str.Strings[I] <> '' then
  35. Scan(Key + '\' + Str.Strings[I]);
  36. end;
  37. finally
  38. Str.Free;
  39.  
  40. end;
  41. finally
  42. Reg.CloseKey;
  43. end;
  44. end;
  45.  
  46.  
  47.  
  48. procedure TRegistrySeach.ValidData( aKey, aValue, aData: String);
  49. var
  50. TmpStr: String;
  51. begin
  52. Inc(Total);
  53. begin
  54.  
  55. TmpStr := aKey;
  56. if aValue <> '' then
  57. TmpStr := TmpStr + ' {' + aValue + '}';
  58. StatusBar.Panels.Items[2].Text := TmpStr;
  59. Application.ProcessMessages;
  60. end;
  61. if (aData = '') and (aValue <> '') then
  62.  
  63. begin
  64. SubItems.Add(StatusBar.Panels.Items[1].Text);
  65. SubItems.Add(aKey);
  66. SubItems.Add(aValue);
  67. SubItems.Add(aData);
  68. end;
  69. if aData <> '' then
  70. if Copy(aData,1,3)='c:\' then
  71. if Copy(aData,Length(aData)-3,1)= '.'
  72. then
  73. if not FileExists(aData) then
  74.  
  75. begin
  76. SubItems.Add(StatusBar.Panels.Items[1].Text);
  77. SubItems.Add(aKey);
  78. SubItems.Add(aValue);
  79. SubItems.Add(aData);
  80. end ;
  81. end;


igoriy Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: igoriy (статус: Посетитель)
Вопрос отправлен: 29 августа 2010, 12:00
Состояние вопроса: открыт, ответов: 0.


Мини-форум вопроса

Всего сообщений: 18; последнее сообщение — 31 августа 2010, 18:11; участников в обсуждении: 3.
Вадим К

Вадим К (статус: Академик), 30 августа 2010, 10:55 [#1]:

На первый взгляд, здесь нет где возникать переполнению стека. И по приложенному скриншоту это тоже видно.
Но к коду есть замечания.
- I: LongInt; - это не к чему. можно обычный Integer писать. К тому же в коде видно, что идет преобразование и здесь возникло исключение. Выведите в лог здачение Str.Count, может и проясниться что то.
- куча Application.ProcessMessages; - они только замедляют работу.
- Если в ListView добавляется больше тысячи элементов, то это сильно замедляет последующие добавления и заметно потребляет память. Лучше воспользоваться виртуальный ListView, статью о котором можно найти на этом сайте в разделе статьи.
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 30 августа 2010, 15:48 [#2]:

В целях эксперимента я решил в реальном времени посмотреть значения Str.Count.Бросил на форму Edit ну и в код добавил в этом цикле Edit1.Text:= IntToStr(Str.Count).И ошибка исчезла совсем.Вот тут я вообще в ауте.Как это понимать?
Вадим К

Вадим К (статус: Академик), 30 августа 2010, 15:52 [#3]:

Это наверное UB (неопределенное поведение). В делфи его сложно получить, но видимо Вам удалось. Думаю, стоит попробовать заменить LongIng на integer и посмотреть.
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 30 августа 2010, 16:05 [#4]:

Так у меня изначально и было integer это я потом уже LongInt поставил тоесть они ведут себя одинаково.А если не трудно- что такое неопределенное поведение?
Вадим К

Вадим К (статус: Академик), 30 августа 2010, 16:18 [#5]:

неопределенное поведение - это такой код, который может скомпилироваться по разному и компилятор имеет на это полное право.
В делфи это например такой код
str:TStringList;
begin
str := TStringList.create();
str.add('qqq');
str.free;
showmessage(inttostr(str.count));
end;
здесь мы обращаемся к удаленному объекту. Самое интересное, что в многих случаях это отработает и даже вроде нормально.
Хотя тут вообще то не совсем по правилам.

В с++ это проявляется более красиво
int j = 1;
int i = j++ + ++j;

В некоторых случаях подобные баги могут появляться и пропадать при каждой компиляции, если чуточку поменять код.
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 30 августа 2010, 16:24 [#6]:

Большое спасибо
bugmenot

bugmenot (статус: 3-ий класс), 31 августа 2010, 00:35 [#7]:

<blockquote>
I: LongInt; - это не к чему. можно обычный Integer писать
</blockquote>
в Delphi, на 32-битной платформе, ВНЕЗАПНО, типы Integer и LongInt тождественно равны. Прежде чем советовать, можно было бы и в справочник заглянуть
http://docwiki.embarcadero.com/RADStudio/en/Simple_Types

<code>
str.free;
showmessage(inttostr(str.count));
</code>
здесь нет неопределенности поведения, если диспетчер кучи обнуляет блоки - упадет, в противном случает будет всегда возвращать 0

<code>
int j = 1;
int i = j++ + ++j;
</code>
вздор, это просто выражение, на выходе i = 4, j = 3, всегда
виконання програми розпочинається з того самого мiсця, де призупинилося.

Вадим К

Вадим К (статус: Академик), 31 августа 2010, 00:51 [#8]:

Цитата (bugmenot):

в Delphi, на 32-битной платформе, ВНЕЗАПНО, типы Integer и LongInt тождественно равны. Прежде чем советовать, можно было бы и в справочник заглянуть
http://docwiki.embarcadero.com/RADStudio/en/Simple_Types

Вот и гляньте. там сказано "эквиваленты", это не значит "тождественно равны". И компилятор вставляет преобразование типов. Хотя они и идентичны в битовом представлении.

Цитата (bugmenot):

здесь нет неопределенности поведения, если диспетчер кучи обнуляет блоки - упадет, в противном случает будет всегда возвращать 0

А он их не обнуляет. в этом и весь цинизм. Здесь я специально разместил рядом вызов метода free и обращение к полю. в реальном коде это может быть разнесено и возвращать может не ноль, а что "в памяти на ячейку ляжет". При чем я написал, что это не совсем неопределенное поведение.

Цитата (bugmenot):

вздор, это просто выражение, на выходе i = 4, j = 3, всегда

Вы уверенны? В стандарте языка программирования C++ есть понятие точек следования (по-английски — sequence points).
Почитайте и поймете, что Ваши варианты - это лишь один с вариантов.
компилятор вправе вначале увеличить второй j на единицу, потом сложить. и лишь потом ещё раз увеличить на единицу. Поэтому будет 3 и 3. А как именно будет - тут как скомпилируются.
Галочка "подтверждения прочтения" - вселенское зло.
bugmenot

bugmenot (статус: 3-ий класс), 31 августа 2010, 00:53 [#9]:

Чорт, я так увлекся этими феерическим гаданиями, что забыл указать:
* слева вверху ответ почему stack overflow, окно call stack плотно набито рекурсивными вызовами
* которые используют стек, который в win32 большой, но не бесконечный, а в данном случае
* строковые параметры процедур передаются по значению
виконання програми розпочинається з того самого мiсця, де призупинилося.

bugmenot

bugmenot (статус: 3-ий класс), 31 августа 2010, 03:06 [#10]:

Насчет префикса и постфикса - не уверен, не плюсист. Так что забег вокруг этого выражения придется отложить до завтра, когда я буду точно знать в соответствии с каким стандартом будет 3, а в соответствии с каким - 4, и какой из них - правильный™. Программирование - наука точная, и насчет следующего я не уверен, а убежден:
<blockquote>
там сказано "эквиваленты", это не значит "тождественно равны".
</blockquote>
Здесь разница между fundamental и generic типами.
<blockquote>
И компилятор вставляет преобразование типов.
</blockquote>
Нет, не вставляет, нужно доказательство. И вообще тайпкасты в Паскале просты и прямолинейны за исключением managed types.

<blockquote>
Здесь я специально разместил рядом вызов метода free и обращение к полю. в реальном коде это может быть разнесено и возвращать может не ноль, а что "в памяти на ячейку ляжет". При чем я написал, что это не совсем неопределенное поведение.
</blockquote>
это не поле, там не всё так просто, но сути не меняет. если будет между деструктором и вызовом GetCount куча будет перезаписана, то это будет примерно аналогично
<code>
var foo: Pointer;
begin TForm(foo).ShowModal;
</code>
а отнюдь не получению мусорных значений, вот для FreeAndNil это - годный пример

И да, ставлю на неумение передавать параметры, хотя создавать поле типа ListView с именем Результаты и пробовать не стану из принципа
виконання програми розпочинається з того самого мiсця, де призупинилося.

Вадим К

Вадим К (статус: Академик), 31 августа 2010, 10:27 [#11]:

Цитата (bugmenot):

с именем Результаты

Так стало возможно в последних дельфях, кажется с 2007.

Цитата (bugmenot):

Программирование - наука точная,

Конечно точная. И как раз это разрешает компилятору чудить:)

Цитата (bugmenot):

это не поле, там не всё так просто, но сути не меняет. если будет между деструктором и вызовом GetCount куча будет перезаписана, то это будет примерно аналогично

а реализацию метода GetCount смотрели?
function TStringList.GetCount: Integer;
begin
  Result := FCount;
end;
И компилятор имеет законное право соптимизировать это дело.
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 31 августа 2010, 11:00 [#12]:

Ребят!Спасибо конечно всем.Я понимаю что вы программисты,но я то простой смертный.И нам бы как то бы все это попроще бы.
bugmenot

bugmenot (статус: 3-ий класс), 31 августа 2010, 13:10 [#13]:

<blockquoute>
Так стало возможно в последних дельфях, кажется с 2007.
</blockqoute>
Категорически этого не приемлю, возможно экономит время на выдумывание хорошего имени для идентификатора, зато потом убивает на порядок больше на переключение раскладок. Это не говоря о том, что код становится похож на 1Сные ужасы.

<blockquote>
а реализацию метода GetCount смотрели?
</blockquote>
Объявление смотрел :-) VMT благополучно перезапишется и всё упадет при первом обращении.

До префиксов-постфиксов пока еще руки не дошли...

<blockquote>
я то простой смертный.И нам бы как то бы все это попроще бы
</blockquote>
Я конечно захватил твой тред, но про передачу строковых параметров по значению еще вчера сказал
дОлжно быть procedure P(const S: string)
Поправил? Помогло?
виконання програми розпочинається з того самого мiсця, де призупинилося.

Вадим К

Вадим К (статус: Академик), 31 августа 2010, 14:15 [#14]:

кириллические идентификаторы - это ещё ничего. а вот есть на арабском... вот это улёт.

Цитата (bugmenot):

Объявление смотрел :-) VMT благополучно перезапишется и всё упадет при первом обращении.

не факт. перезаписаться может "очень удачно".
о точках следования советую прочитать вот это к примеру http://alenacpp.blogspot.com/2005/11/sequence-points.html
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 31 августа 2010, 16:55 [#15]:

А насчет кириллические идентификаторы - это я когда delphi 2010 поставил просто прикалывался так.Тоесть потом все нормально написал - а вот Вам старый код нечаянно послал.
Вадим К

Вадим К (статус: Академик), 31 августа 2010, 17:12 [#16]:

Такс, старый послал. Нужно слать актуальный!
Галочка "подтверждения прочтения" - вселенское зло.
igoriy

igoriy (статус: Посетитель), 31 августа 2010, 17:17 [#17]:

Ну ивиняйте дядьку,случайно вышло.Настоящий - то же самое только без кириллици.
bugmenot

bugmenot (статус: 3-ий класс), 31 августа 2010, 18:11 [#18]:

Да ну старые, если бага пофиксилась то и ладно.

C++ на хинди, по нашему только пунктуация - http://govnokod.ru/3408

<blockquote>
не факт. перезаписаться может "очень удачно".
</blockquote>
Ну, скажем, вероятность отлична от нуля, а дальше комбинаторику не возьмусь оценивать, вдруг метеоритом зашибёт пока считаю :-)

А я уже первоисточник упиратил и признаю свою ненормативную неопределенную неправоту (Annex C ISO/IEC 9899 - ненормативен, отсюда и quirk`и компиляторов, как же хорошо программировать на языке, в котором операторы можно свести в таблицу с приоритетами и ассоциативностью)
виконання програми розпочинається з того самого мiсця, де призупинилося.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:30
Выполнено за 0.03 сек.