Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2011.06.26;
Скачать: [xml.tar.bz2];

Вниз

Процедура FillChar и динамические массивы   Найти похожие ветки 

 
Baks   (2011-01-28 00:51) [0]

Какими последствиями грозит выполнение следующего кода:

type
 TMySLst = array of String;

 TMyRec = record
   MySLst: TMySLst;
   ID: Integer;
 end;

procedure Test;
var
 MyRec: TMyRec;
begin
 FillChar(MyRec, SizeOf(MyRec), 0);

 SetLength(MyRec.MySLst, 5);
end;

?


 
tesseract ©   (2011-01-28 01:02) [1]

AccessViolation  или перетирание указателей и плавающий баг. SizeOf(MyRec) вообще должен выдать 8 - но наверно этого хватит.


 
Германн ©   (2011-01-28 01:08) [2]


> AccessViolation

AV вряд ли будет, к сожалению. :(


 
tesseract ©   (2011-01-28 01:10) [3]


> AV вряд ли будет, к сожалению. :(


Сразу не будет. Будет потом в самых неожиданных местах.


 
Baks   (2011-01-28 01:33) [4]

Как я понимаю повреждение данных за пределами памяти выделенной под MyRec не должно произойти т.к. SizeOf вернёт 8, а FillChar затрёт указатель на MySLst (4) и обнулит ID (4).


 
tesseract ©   (2011-01-28 01:37) [5]


> а FillChar затрёт указатель на MySLst (4)


Скорее всего так и будет. Но тонкости возможны. При обращении к массиву получишь ты свой AV.


 
Германн ©   (2011-01-28 01:41) [6]


> FillChar затрёт указатель на MySLst (4) и обнулит ID (4).

Да.


 
tesseract ©   (2011-01-28 01:52) [7]

Да и как ты думаешь, что произойдет, когда будет dispose по дин массиву ?


 
Baks   (2011-01-28 01:57) [8]


> При обращении к массиву получишь ты свой AV


Интересно то, что при вызове SetLength(MyRec.MySLst, 5) никакого AV не происходит. А MyRec.MySLst содержит 5 пустых строк.


> Да и как ты думаешь, что произойдет, когда будет dispose
> по дин массиву ?


Не знаю.


 
Германн ©   (2011-01-28 02:15) [9]


> Интересно то, что при вызове SetLength(MyRec.MySLst, 5)
> никакого AV не происходит.

Интересно. Сделай тестовый проект и выложи его куда-нибудь. Пока сабж только "твои предположения".

P.S. AV как раз тем и страшен, что неуловим на этапе отладки! Можно туеву хучу лет отлаживать программу в отладчике и не иметь никаких проблем. А на туева хуча + 1 год получить AV! И как правило эта ошибка возникает уже после того, как ПО передано заказчику. :(


 
tesseract ©   (2011-01-28 02:28) [10]


> никакого AV не происходит. А MyRec.MySLst содержит 5 пустых
> строк.


Неее Delphi хранит размер указаетеля в отдельной области. Поэтому setlength только его размер увеличивает - прямого обращения по адресу не происходит. Если у тебя такие вопросы возникают - поиграйся с Си. Там быстро с указателями порядок наступает.


 
Sapersky   (2011-01-28 04:24) [11]

AV не будет, может быть утечка в том случае, если массив перед FillChar не пустой. Но поскольку в данном конкретном случае он пустой - всё OK.
nil/0 для дин.массивов/строк - это нормальное состояние, означает "нет данных". Вот если туда попадёт мусор (случайное значение <> 0) - тогда будет AV, поскольку компилятор посчитает этот мусор за предыдущее значение строки и попытается её освободить.
FreeMem/TObject.Free, кстати, тоже нормально отрабатывают на nil (ничего не делают).


 
oxffff ©   (2011-01-28 09:50) [12]


> Baks   (28.01.11 00:51)  
> Какими последствиями грозит выполнение следующего кода:
>
> type
>  TMySLst = array of String;
>
>  TMyRec = record
>    MySLst: TMySLst;
>    ID: Integer;
>  end;
>
> procedure Test;
> var
>  MyRec: TMyRec;
> begin
>  FillChar(MyRec, SizeOf(MyRec), 0);
>
>  SetLength(MyRec.MySLst, 5);
> end;
>
> ?


Усе будет нормуль. Если код имеено такой. Для записей с управляемыми полями ставляется вызов конструктора по умолчанию, который их инициализирует в 0.


 
oxffff ©   (2011-01-28 09:53) [13]


>  FillChar(MyRec, SizeOf(MyRec), 0);


Ето вообще зачем?


 
RWolf ©   (2011-01-28 10:32) [14]


>  Для записей с управляемыми полями ставляется вызов конструктора
> по умолчанию, который их инициализирует в 0.

то есть, MyRec можно и не обнулять, несмотря на то, что она на стеке?


 
RWolf ©   (2011-01-28 10:35) [15]

или конструктором обнуляются только управляемые поля?


 
han_malign   (2011-01-28 10:54) [16]


> или конструктором обнуляются только управляемые поля?

- угадал... См. System._Initialize/_Finalize...
(Если что - _Finalize делается в неявной try/finally секции при выходе стековой структуры с магическими полями из области видимости)
Эти функции также вызываются при типизированном new/dispose(но не при GetMem/FreeMem), и их можно вызывать явно(убрав магическое подчеркивание), если по каким то причинам используются другие методы выделения памяти(это удобнее нудного обнуления магических полей, и структура легко масштабируется)...


 
DiamondShark ©   (2011-01-28 11:37) [17]

Сколько профессионалов, однако


 
Baks   (2011-01-28 18:13) [18]

Этот код конечно неправильный, но если такая ошибка допушена, то как я
понял к большим проблемам (кроме утечки памяти) это не приведёт.
Правильно?


 
Leonid Troyanovsky ©   (2011-01-28 18:30) [19]


> Baks   (28.01.11 18:13) [18]

> понял к большим проблемам (кроме утечки памяти) это не приведёт.

Маловато будет?

--
Regards, LVT.


 
Sha ©   (2011-01-28 18:53) [20]

> Baks   (28.01.11 18:13) [18]

Интересно стало, а какие проблемы считаются большими?
Нечто большее, чем неработоспособность программы?
Это, наверно, когда она приносит вред, а не пользу?
Ну, такую программу еще надо постараться написать без ошибок.
А с таким отношением, скорее всего, не получится.
Полегчало :-)


 
Baks   (2011-01-30 12:33) [21]

Подскажите ещё, если сделать так:

type
TMySLst = array of String;

TMyRec = record
  MySLst: TMySLst;
  ID: Integer;
end;

function Test: TMyRec;
begin
 Result.
end;

Если запустить функцию дважды то при втором входе Result не будет пустым
изначально. Подскажите, как нужно очистить Result в данном случае?


 
jack128_   (2011-01-30 13:10) [22]

Finalize(Result);


 
Baks   (2011-01-30 13:34) [23]

А если очистить так:

SetLength(Result.MySLst, 0);
ID := 0;

Так, будет правильно? Не будет утечки памяти?


 
Baks   (2011-01-30 21:25) [24]

Обнаружил, что вызов данной функции в цикле приводит к утечке памяти. Почему?

 TMyRec = record
   MStr: String;
   UStr: String;
   ID: Integer;
 end;

function GetER: TMyRec;
begin
 ZeroMemory(@Result, SizeOf(Result));

 Result.MStr := "Text";
 Result.UStr := "Text";
 Result.ID := 1;
end;

При втором и последующих входах Result содержит прежние данные.
Чтобы их очистить я выполняю ZeroMemory(@Result, SizeOf(Result));
Но обнаружил, что если эту процедуру убрать, то утечки памяти не будет.
Почему? И как правильно в данном случае очищать Result?


 
oxffff ©   (2011-01-30 21:42) [25]


> Baks   (30.01.11 21:25) [24]
> Обнаружил, что вызов данной функции в цикле приводит к утечке
> памяти. Почему?


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


 
Baks   (2011-01-30 21:50) [26]


> минуя семантику управляемых типов в данном случае динамических
> массивов


Так, здесь же нет дин. массива.

TMyRec = record
  MStr: String;
  UStr: String;
  ID: Integer;
end;

Или имеется ввиду String?


 
Baks   (2011-01-30 21:59) [27]

Всё, кажется разобрался. Если сделать например String[250], то память остаётся неизменной. Я забыл, что строки это тоже дин. массивы.


 
Sha ©   (2011-01-30 22:16) [28]

Кошмар. Сплошное латание дыр.
1. Откуда берется утечка, а точнее ошибка в программе из-за которой ты теряешь данные, ты так и не понял.
2. Не разобрался с возвратом записи в качестве результата, а это запросто может стать в твоем случае еще одними граблями.


 
Baks   (2011-01-30 22:25) [29]

Почему не разобрался?
При выполнении ZeroMemory не освобождается память выделенная для содержимого строк.


> Не разобрался с возвратом записи в качестве результата


Что имеется ввиду? Хотелось бы подробней.


 
Sha ©   (2011-01-30 22:35) [30]

> При выполнении ZeroMemory не освобождается память выделенная для содержимого строк.

Она также не освобождается при выполнении оператора i:=i+1;
Освободить-то как?

>> Не разобрался с возвратом записи в качестве результата
> Что имеется ввиду? Хотелось бы подробней.

[25] изучи.
Твой ZeroMemory затирает "прежние данные", но вовсе не там, где ты думаешь.


 
Baks   (2011-01-30 22:40) [31]

Ну так как же тогда освобождать эти данные на входе в функцию?


 
Baks   (2011-01-30 22:41) [32]

Конечно ZeroMemory здесь не подходит. Это понятно.


 
Sha ©   (2011-01-30 22:44) [33]

Тут не в нем дело даже, а в том, что утечка может произойти из-за копирования записи.
Короче не используй ты функцию, пока не понял, что к чему.


 
Sha ©   (2011-01-30 23:14) [34]

Опечатался:
> что утечка может произойти
> что ошибка может произойти

При копировании утечки, очевидно, не будет.


 
Sha ©   (2011-01-30 23:23) [35]

В общем вот пример, чтобы было ясно, о чем речь:

type
 TRec = record
   s: string;
   end;

function GetRec: TRec;
begin;
 Result.s:=Result.s + "a";
 end;

var
 r: TRec;

procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
begin;
 for i:=1 to 3 do begin;
   r.s:=r.s + "a";
   r.s:=r.s + "b";
   end;
 Caption:=r.s;
 end;

procedure TForm1.Button2Click(Sender: TObject);
var
 i: integer;
begin;
 for i:=1 to 3 do begin;
   r:=GetRec;
   r.s:=r.s + "b";
   end;
 Caption:=r.s;
 end;


 
Baks   (2011-01-31 00:00) [36]

Ну, так при входе в GetRec нужно обязательно Result очищать.
А так при повторном входе, мы фактически используем остатки от прошлого выполнения. Так?


 
Baks   (2011-01-31 00:07) [37]

В данном случае надо сделать так:

procedure GetRec(var R: TRec);
begin;
 R.s:=R.s + "a";
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i: integer;
begin;
for i:=1 to 3 do begin;
  GetRec(r);
  r.s:=r.s + "b";
  end;
Caption:=r.s;
end;


 
Sha ©   (2011-01-31 00:09) [38]

> Baks   (31.01.11 00:00) [36]

Ты пример [35] запускал?
Если да, то должен понять, что никакая очистка Result в GetRec
не позволит получить в Button2Click тот же Caption, что и в Button1Click.


 
Sha ©   (2011-01-31 00:11) [39]

> Baks   (31.01.11 00:07) [37]

Ага.
Осталось научиться не терять данные.


 
Baks   (2011-01-31 00:22) [40]

Запускал. Естественно, очистка не поможет получить такой тезультат, как в Button1 таким способом:

function GetRec: TRec;
begin;
 Result.s:=Result.s + "a";
end;

это нельзя делать. К чему мы прибавляем "а"? К каким-то остаткам.


 
Кто б сомневался ©   (2011-01-31 01:32) [41]

Я кстати вместо FillChar, юзаю апишную ZeroMemory - т.к. в FillChar все равно ее вызывает потом.


 
Германн ©   (2011-01-31 01:53) [42]


> Кто б сомневался ©   (31.01.11 01:32) [41]
>
> Я кстати вместо FillChar, юзаю апишную ZeroMemory - т.к.
>  в FillChar все равно ее вызывает потом.

Очень неудачный топик для подобного заявления. Примите и прочь! :)


 
Baks   (2011-01-31 03:04) [43]


> Очень неудачный топик для подобного заявления


Да, лучше не напоминать, я их (FillChar, ZeroMemory) теперь обеих боюсь.


> а это запросто может стать в твоем случае еще одними граблями


Похоже я наступил на детские грабли, а это ещё неприятнее :)


 
Sha ©   (2011-01-31 08:01) [44]

> Baks   (31.01.11 00:22) [40]
> function GetRec: TRec;
> begin;
>   Result.s:=Result.s + "a";
>   end;
> это нельзя делать. К чему мы прибавляем "а"? К каким-то остаткам.Baks  

К временной записи, которую завел компилятор.
А если нельзя, то почему же ты реботаешь с временной записью в [24] ?

> Baks   (31.01.11 03:04) [43]
> Да, лучше не напоминать, я их (FillChar, ZeroMemory) теперь обеих боюсь.

Чего их бояться? Это все равно, что бояться использовать для строк оператор
integer(s):=0;
который просто обнулит указатель на строку, а сама строка останется лежать в ОП. Он не для этого. Присвоить строке пустое значение можно и другими способами.


 
Baks   (2011-02-01 13:54) [45]


> почему же ты реботаешь с временной записью в [24] ?


Я её для этого очищаю и из неё ничего не читаю. И к прежнему содержимому не прибавляю.


 
Sha ©   (2011-02-02 10:10) [46]

> Baks   (01.02.11 13:54) [45]
> Я её для этого очищаю

В итоге подсчет ссылок для строк, которые ты сформируешь во временной записи, работает неверно. Утечка.
Лучше не делать этого.


 
имя   (2011-03-12 18:49) [47]

Удалено модератором



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2011.06.26;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.004 c
2-1300783231
novichek
2011-03-22 11:40
2011.06.26
EXISTS или IN


15-1300117961
Сергей К.
2011-03-14 18:52
2011.06.26
Bob Marley - no woman, no cry


15-1297596752
KilkennyCat
2011-02-13 14:32
2011.06.26
Любителям собирать компьютеры


2-1300549046
RUu
2011-03-19 18:37
2011.06.26
adodataset


2-1300262871
fred
2011-03-16 11:07
2011.06.26
AV





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский