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

Вниз

Насколько безопасен SetLength   Найти похожие ветки 

 
TUser ©   (2004-05-27 16:00) [0]

Насколько безопасен SetLength при работе с дин. массивами? Всегда ли он корректно выделяем/высвобождает память? Раньше никаких нареканий у меня не было, но сейчас ситуация такая. Есть код, который нормально работает. Теперь надо его запустить много раз. При этом вызовы соотв. функций осуществляются последовательно. Довольно часто вылетает AV и вываливается CPU window. Подозреваю, что это связано с тем, что какая-то память кушается и не освобождается в предыдущей итерации (хотя не уверен, что причина точно в этом). Первая итерация всегда происходит нормально. При трассировке удается дойти до различных участков кода, чаще всего остановка происходит именно на SetLength. Хотя и не обязательно, может произойти ошибка, например, на таком участке кода
if FileExists(FileName) then
  try
  sl:=TStringList.Create;
  sl.LoadFromFile(FileName) // <-- здесь
  finally
  sl.Free
  end;
Первая итерация всегда происходит нормально, на одной из дальнейших происходит ошибка. При этом при одинаковых исходных данных для некой итерации ошибка может произойти, а может и не произойти. Короче, совершенно не понимаю, где могут быть грабли. Буду рад услышать ценные советы по этому поводу, хотя понимаю, что тут скорее всего надо копать конкретную программу, а не слушать подобные рассуждения.


 
Digitman ©   (2004-05-27 16:04) [1]

непонятно, где здесь "итерация"
этот термин тесно связан с термином/концепцией "цикл"
цикл же в приведенном примере вряд ли кто наблюдает


 
Тимохов ©   (2004-05-27 16:09) [2]

Не в тему вопроса, но все же - вы не читали тесты нашего многоуважаемого коллеги, которые он проводит при приеме на работу?

Один из вопросов:

что плохого в таком коде?


> try
>   sl:=TStringList.Create;
>   sl.LoadFromFile(FileName) // <-- здесь
> finally
>   sl.Free
> end;


 
Sandman25+1   (2004-05-27 16:12) [3]

[2] Тимохов ©   (27.05.04 16:09)
Если вызывается 1 раз и sl - модульная/член класс, то еще ничего.
Бывало и хуже.

try
Screen.Cursor := crHourGlass;
...
except
 on E:Exception do Application.ShowException(E);
end;
Screen.Cursor := crDefault;

Такое ощущение, что человек не был знаком с try/finally.


 
Ega23 ©   (2004-05-27 16:12) [4]

> try
>   sl:=TStringList.Create;
>   sl.LoadFromFile(FileName) // <-- здесь
> finally
>   sl.Free
> end;

ИМХО,

try
sl:=TStringList.Create;
try
  sl.LoadFromFile(FileName) // <-- здесь
except
 ShowMessage
end;
finally
sl.Free;
end;

Это имелось ввиду?


 
Тимохов ©   (2004-05-27 16:14) [5]


> Ega23 ©   (27.05.04 16:12) [4]
> > try

нет - не это.

имелось с виду, что конструктор может окончится с ошибкой, значение sl присвоено не будет, но free у него вызван будет - в общем случае av.


 
WebErr ©   (2004-05-27 16:27) [6]


> Тимохов ©   (27.05.04 16:14) [5]

Клёво, а вот я не угадал, где грабли, а где ещё пару таких тестов достать можно? 8)


 
Ega23 ©   (2004-05-27 16:33) [7]

В общем случае:

procedure TObject.Free;
asm
       TEST    EAX,EAX
       JE      @@exit
       MOV     ECX,[EAX]
       MOV     DL,1
       CALL    dword ptr [ECX].vmtDestroy
@@exit:
end;

Может я что-то не так понимаю, но разве не проверяется в
       TEST    EAX,EAX
экземпляр класса на nil?


 
Тимохов ©   (2004-05-27 16:38) [8]


> Может я что-то не так понимаю, но разве не проверяется в
>
>        TEST    EAX,EAX
> экземпляр класса на nil?

кто-нибудь говорил про класс?


 
Ega23 ©   (2004-05-27 16:41) [9]

имелось с виду, что конструктор может окончится с ошибкой, значение sl присвоено не будет, но free у него вызван будет - в общем случае av.

Если это не про класс, то про что?


 
Тимохов ©   (2004-05-27 16:42) [10]


> Ega23 ©   (27.05.04 16:41) [9]

sl может быть локальной переменной процедуры, причем не проинициализированной.

Думаете не будет av?


 
Ega23 ©   (2004-05-27 17:12) [11]

sl может быть локальной переменной процедуры, причем не проинициализированной.

Думаете не будет av?

1. Я бы попросил ко мне на "ты". К вам на "вы" могу, если вам так проще будет.
2. Возможно мы друг-друга не понимаем, или говорим о разных вещах.
Насколько понял я:

где-то (возможно внутри данной функции) есть
var
sl:TStringList;

далее, в какой-то функции идёт вызов:

try
try
 sl:TStringList.Create;
 sl:TStringList.LoadFromFile(FileName);
except on E:Exception do
 ShowMessage(E.Message);
end;
finally
 sl.Free;
end;

Речь шла о том, что exception может возникнуть в момент отработки конструктора. Тогда (я могу ошибаться, но насколько мне известно) память, начавшая выделяться под данный экземпляр класса освобождается, самому sl приравнивают nil.
Дальше мы видим наш ShowMessage с текстом об ошибке.
Дальше проваливаемся в секцию finally sl.Free.
Но, насколько мне известно, Free отработает как раз от TObject? Проверит на nil, если <>nil, то вызовет деструктор.

Или я не прав?


 
Тимохов ©   (2004-05-27 17:17) [12]


> самому sl приравнивают nil.

в этом вы ошибаетесь.


 
Ega23 ©   (2004-05-27 17:20) [13]

> самому sl приравнивают nil.   в этом вы ошибаетесь.

Точно? Иначе мне очень уважаемым мною людям придётся претензии ставить.


 
Anatoly Podgoretsky ©   (2004-05-27 17:26) [14]

А где  Насколько безопасен SetLength

 sl:=TStringList.Create;
 try

должен быть здесь, иначе при ошибке будет еще одна ошибка.


 
Игорь Шевченко ©   (2004-05-27 17:28) [15]


> Точно? Иначе мне очень уважаемым мною людям придётся претензии
> ставить.


Точно. Откуда конструктор может знать, какой переменной присваивается его результат ?


 
Ega23 ©   (2004-05-27 17:28) [16]

АП нас рассудит!  :о)
Анатолий, объясните мне, убогому: получается, что от ошибки в конструкторе невозможно закрыться? Только выход из процедуры (функции) память освободит?


 
Anatoly Podgoretsky ©   (2004-05-27 17:30) [17]

Тимохов ©   (27.05.04 16:42) [10]
Может быть и глобальной переменной, полем класса, но имееющим в данный момент не нулевое значение, например старое от предыдущей операции.


 
Тимохов ©   (2004-05-27 17:30) [18]


> Ega23 ©   (27.05.04 17:20) [13]

точно.
т.е. если в таком коде
o := tmyobject.create();
в конструкторе класса tmyobject.create была ошибка, то o не изменит свое значение.

делать надо так, как говорит Анатолий: т.е. до try/

можно, конечно,  и после try, но тогда перед try нужно явно обнилить переменную.


 
Shkut ©   (2004-05-27 17:31) [19]

Не ссорьтесь, Делфи 7 на подобного рода код выдет предупреждение, и пока конструктор не будет выненсен за пределы try, компилятор будет "варнякать".


 
Тимохов ©   (2004-05-27 17:32) [20]


> Ega23 ©   (27.05.04 17:28) [16]
> АП нас рассудит!  :о)

вы, похоже, про дургое говорите.


> Только выход из процедуры (функции) память освободит?


вот это очем?


 
Anatoly Podgoretsky ©   (2004-05-27 17:35) [21]

Shkut ©   (27.05.04 17:31) [19]
Это хорошо


 
Anatoly Podgoretsky ©   (2004-05-27 17:36) [22]

Ega23 ©   (27.05.04 17:28) [16]
Про что ты?


 
default ©   (2004-05-27 17:37) [23]

Shkut ©   (27.05.04 17:31) [19]
даже если переменная объекта глобальна?


 
Sandman25+1   (2004-05-27 17:38) [24]

>Только выход из процедуры (функции) память освободит?

Так память освобождается только для AnsiString, динамических массивов и интерфейсов.


 
Ega23 ©   (2004-05-27 17:41) [25]

вот это очем?

Так, ещё раз.
o:=TMyObject.Create;
Начал отрабатывать конструктор, начала заниматься память под о. Затем - сбой.
1. Чему будет равно о:
     а) Чему было равно до o:=TMyObject.Create;
     б) nil;
     в) Неизвестно
     г) Чему-то другому?
2. Освободиться ли та память, которая успела выделиться для о ДО сбоя?

Насчёт того, что o будет равно nil, я их всегда nil ПЕРЕД конструктором присваиваю. Так что, наверное, ответ на первый вопрос - а.
А вот со вторым мне не понятно.


 
Anatoly Podgoretsky ©   (2004-05-27 17:42) [26]

Sandman25+1   (27.05.04 17:38) [24]
Скажем так для субъектов с автоматическим контролем времени жизни, выше придены именно они.


 
Тимохов ©   (2004-05-27 17:44) [27]

1. - a
2. если сбой был в конструкторе, то успеет.

ЗЫ. Конструктор не выделяет память. Конструктор мало чем отличается от метода в тот момент, когда начал выполняться.
Отличия 2:
1. Исключение в конструкторе генерит удаление объекта (вызов деструктора и очистку памяти)
2. ключевое слово constructor заставляет компилитор сгенерить код отличный от вызова простого метода - сначала создается объект (NewInstance) затем вызов конструктора.


 
Тимохов ©   (2004-05-27 17:47) [28]

эх, спросил человек об одном а ему 27 постов лабуды какой-то.:)))

АВТОРУ.
Не думаю, что на ваш ответ без кода можно ответить.
SetLength вполне безопасен. Дело в вашем коде.


 
Sandman25+1   (2004-05-27 17:48) [29]

[26] Anatoly Podgoretsky ©   (27.05.04 17:42)

Каюсь, я преследовал личную цель - хотел убедиться, что меня не поправят и не добавят еще что-нибудь в этот список.


 
Anatoly Podgoretsky ©   (2004-05-27 17:49) [30]

Тимохов ©   (27.05.04 17:44) [27]
Не совсем соглащусь, для илюстрации два вызова, один как конструктор, а второй как метод

O := TO.Create
O.Create


 
Anatoly Podgoretsky ©   (2004-05-27 17:51) [31]

Sandman25+1   (27.05.04 17:48) [29]
Ну добился этого :-)


 
Тимохов ©   (2004-05-27 17:51) [32]


> Sandman25+1   (27.05.04 17:48) [29]
> Каюсь, я преследовал личную цель - хотел убедиться, что
> меня не поправят и не добавят еще что-нибудь в этот список.

:))
Я тоже не против покаятся - я когда видел ваш пост пожалел, что у меня нет карандаша - честное слово :))))


> Anatoly Podgoretsky ©   (27.05.04 17:49) [30]

Про второй случай я не говорил. Честно говоря даже не очень знаю, что будет - т.к. никогда так не делал.
Думаю что O.Create просто вызовет тело create как подпрограмму - никакого объект не создасться.


 
Anatoly Podgoretsky ©   (2004-05-27 17:54) [33]

Не создастся поскольку уже создан, по сути должна быть переинициализация, но я никогда не пользовался. Вопрос кстати часто фигурировал, разбирали по корочкам, может кто ни будь подробнее расскажет.


 
Sandman25+1   (2004-05-27 17:55) [34]

[32] Тимохов ©   (27.05.04 17:51)

Не совсем понимаю. Вы хотели написать комментарий к моему посту? К какому именно?


 
Тимохов ©   (2004-05-27 17:55) [35]


> Anatoly Podgoretsky ©   (27.05.04 17:51) [31]

думаю понимаю, что вы говорите
вот это

"ключевое слово constructor заставляет компилитор сгенерить код отличный от вызова простого метода"

надо заменить на

"ключевое слово constructor в сочетании с именем класса заставляет компилитор сгенерить код отличный от вызова простого метода"


 
Ega23 ©   (2004-05-27 17:57) [36]

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

Это понятно. возможно я неточно выразился. я имел ввиду следующее:
TMyObj=class(TObject)
......
public
constructor Create;
destructor Destroy; override;
end;

constructor TMyObj.Create;
begin
inherited;
 ......
Какие-то другие действия
.......
end;

destructor TMyObj.Destroy;
begin
.....
Какие-то действия
.....
inherited;
end;

Сбой пришёл откуда-то из inherited конструктора. "Какие-то действия" - допустим, создание (удаление) каких-то других объектов.

Что будет в этом случае.


 
Тимохов ©   (2004-05-27 17:57) [37]


> Sandman25+1   (27.05.04 17:55) [34]

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

По поводу строк, дин мас и интерфейсов я бы добавил именно, то что добавли АП, т.к. это более широкое понятие.


 
Anatoly Podgoretsky ©   (2004-05-27 17:59) [38]

Тимохов ©   (27.05.04 17:55) [35]
Хорошая редакция. Борланд иногда исправляет терминологию в своих справках. Например виртуальный класс, теперь базовый класс


 
Sandman25+1   (2004-05-27 18:01) [39]

[37] Тимохов ©   (27.05.04 17:57)

Да, я ждал не синего карандаша. Мы же не в той конференции :)
Просто я не был уверен, что в Delphi 8 не добавили чего-нибудь новенького...


 
Тимохов ©   (2004-05-27 18:01) [40]


> Ega23 ©   (27.05.04 17:57) [36]

Это явно описано в мануале дельфи.
В случае генерации исключения в конструкторе будет вызыван деструктор, зачем отвобождена память. Именно поэтому в деструкторе нужно предполагать, что не все члены класса могут быть до конца инициализированы.

Например я всегда пишу.
destructor TMyObj.Destroy;
begin
  if kList <> nil then
  begin
     for I := 0 to kList.Count-1 do tobject(kList).free;
     kList.Free();
  end;
  inherited;
end;



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

Форум: "Основная";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.044 c
14-1084787238
Внук
2004-05-17 13:47
2004.06.06
Снова о комедиях


3-1084455789
tchn
2004-05-13 17:43
2004.06.06
master_detail+lookup=непонятки


3-1084525896
ZiaTron
2004-05-14 13:11
2004.06.06
EDBEngineError with Message : Unknow database


1-1085109921
Апач
2004-05-21 07:25
2004.06.06
Структура данных


14-1084762100
тихий вовочка
2004-05-17 06:48
2004.06.06
исчезновение информации с винта





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский