Форум: "Основная";
Текущий архив: 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