Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.07.25;
Скачать: CL | DM;

Вниз

Особенности вызовов конструкторов   Найти похожие ветки 

 
jack128 ©   (2004-07-06 17:50) [0]

Как известно конструктор объекта можно использовать в двух контекстах

1) как классовый метод
 Instance := TMyCoolObject.Create();
2) как обычный метод
 Instance.Create();

а вот код который компилятор ренерит при вызове коструктора можно разделить на три группы
1)
 Instance := TMyCoolObject.Create();
в этом случае происходит вызов _ClassCreate(это влечет за собой вызов NewInstance а потом вызов собственно тела конструктора. если в конструкторе возникло исключение, то вызывается FreeInstance

2) Instance.Create();
 последовательность вызовов таже, что и в первом случае, но в _ClassCreate передается флаг, указывающий на то что конструктор вызывается как обычный метод и вызова NewInstance не поисходит. Однако если в конструкторе возникло исключение, то теста на этот флаг не делается и соответственно объект уничтожается.
 Instance.Create(); //если здесь возникло исключение, то Instance - уничтожается

3)
 constructor TChildMyCoolObject.Create;
 begin
    inherited Create(); // тут происходит просто передача управления в унаследованный конструктор. Безо всяких дополнительных вызовов.
 end;

Собственно все эти исследования меня заставила провести особенность второго варианта. Если во время вызова Instance.Create() возникло исключение, то объект уничтожается. Чем вызвано такое (ИМХО нелогичное) решение??


 
Reindeer Moss Eater ©   (2004-07-06 18:02) [1]

Если во время вызова Instance.Create() возникло исключение, то объект уничтожается.

А он вообще создается?


 
jack128 ©   (2004-07-06 18:03) [2]


> А он вообще создается?
предпологается, что объект уже создан..


 
Reindeer Moss Eater ©   (2004-07-06 18:05) [3]

Создается ли объект в результате вызова конструктора с несозданным экземпляром?

nonexistingone.Create(nil)


 
jack128 ©   (2004-07-06 18:05) [4]

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


 
jack128 ©   (2004-07-06 18:07) [5]


> nonexistingone.Create(nil)
нет, конечно.

> в _ClassCreate передается флаг, указывающий на то что конструктор
> вызывается как обычный метод и вызова NewInstance не поисходит

procedure       _ClassCreate;
asm
       { ->    EAX = pointer to VMT      }
       { <-    EAX = pointer to instance }
       PUSH    EDX
       PUSH    ECX
       PUSH    EBX
       TEST    DL,DL
       JL      @@noAlloc
       CALL    dword ptr [EAX].vmtNewInstance


 
Reindeer Moss Eater ©   (2004-07-06 18:07) [6]

Если во время вызова Instance.Create() возникло исключение, то объект уничтожается.

А он вообще создается?


 
jack128 ©   (2004-07-06 18:12) [7]

блин, пример

type
 TTest = class(TObject)
 public
   constructor Create;
 end;

var
 IsClassMethod: boolean = True;

procedure TForm1.Button1Click(Sender: TObject);
var
 t: TTest;
begin
 IsClassMethod := True;
 t := TTest.Create(); // объект создан
 try
   IsClassMethod := False;
   t.Create(); // так как поднялось исключение, то объект уничтожается
 finally
   t.Free; // t - битый указатель
 end ;
end;

{ TTest }

constructor TTest.Create;
begin
 if not IsClassMethod then
   raise Exception.Create("");
end;


 
Reindeer Moss Eater ©   (2004-07-06 18:22) [8]

Ах вот ты о чем.
Я же думал что ты вызываешь конструктор у не инициализированного t и удивляешься тому, что создаваемый (якобы) конструктором объект сразу уничтожается.

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


 
Digitman ©   (2004-07-06 18:27) [9]

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


 
jack128 ©   (2004-07-06 18:29) [10]


> Зачем вызывать конструктор используя конкретный экземпляр?
> Ну хоть одна причина для этого есть?

но синтаксически же такое разрешено. вот том же С++ конструктор для созданного объекта нельзя вызвать и никаких вопросов не возникает..
А уж если в паскале такое разрешили, то должна же быть какая то причина.


 
Юрий Зотов ©   (2004-07-06 18:29) [11]

> Reindeer Moss Eater ©   (06.07.04 18:22) [8]

> Ну хоть одна причина для этого есть?

Inherited Create внутри конструктора - это какой вызов, как Вы думаете?


 
jack128 ©   (2004-07-06 18:31) [12]


> Юрий Зотов ©   (06.07.04 18:29)
> > Reindeer Moss Eater ©   (06.07.04 18:22) [8]
>
> > Ну хоть одна причина для этого есть?
>
> Inherited Create внутри конструктора - это какой вызов,
> как Вы думаете?
но вызов то реализовать по разному для inherited Create() и Instance.Create().  по сути - это разные вещи ..


 
Юрий Зотов ©   (2004-07-06 18:31) [13]

> jack128

Кстати, [11] - это и ответ на Ваш вопрос тоже. Исключение в цепочке унаследованных конструкторов тоже должно уничтожать свежесозданный объект.


 
jack128 ©   (2004-07-06 18:32) [14]


> но вызов то реализовать
но вызовы то реализованы по разному


 
Reindeer Moss Eater ©   (2004-07-06 18:38) [15]

но синтаксически же такое разрешено.

синтаксически и такое вот разрешено:

procedure TForm1.Btn1Click(Sender : TObject);
var mycomp : tcomponent;
begin
caption := mycomp.name;
end


 
Гаврила ©   (2004-07-06 18:45) [16]


> Чем вызвано такое (ИМХО нелогичное) решение??


Думаю, это недоработка Борланда.
А все остальные участники ветки похоже не поняли, о чем речь вообще идет


 
jack128 ©   (2004-07-06 18:53) [17]


> Исключение в цепочке унаследованных конструкторов тоже должно
> уничтожать свежесозданный объект.
да не должно. вызов унаследованного конструктора - это вызов унаследованного конструктора и нечего более. Вызова _ClassCreate не происходит и соответственно объект не уничтожается.

сравните

constructor TTest.Create();
begin
 raise Exception.Create();
end;

constructor TChildTest.Create()
begin
 try
  inherited Create; // исключение в унаследованном конструкторе, но объект жив
 except
 end;  
end;

try
 TTest.Create() // исключение в конструкторе и объект помер
except
end;

> синтаксически и такое вот разрешено:
>
> procedure TForm1.Btn1Click(Sender : TObject);
> var mycomp : tcomponent;
> begin
> caption := mycomp.name;
> end
конечно - это же логическая ошибка, а не синтаксическая. Использовать битый указатель безнаказанно нигде нельзя.
но тут то другой случай. Я вообще не говорил про ошибку, мне интересно почему сделано именно так, а не иначе. Почему вдруг объект должен уничтоваться во случае 2) ?


> Думаю, это недоработка Борланда.
А я так верил в его святость  :-))

> А все остальные участники ветки похоже не поняли, о чем
> речь вообще идет
еще не вечер ;-)


 
GuAV ©   (2004-07-06 22:30) [18]

Мда. Когда я вернусь сюда, я обязательно поищу эту вету в архиве. Если ситуация не прояснится - напишу письмо Борланд.


> еще не вечер ;-)

уже темнеет ;-)



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

Текущий архив: 2004.07.25;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.025 c
14-1089003967
Vlad Oshin
2004-07-05 09:06
2004.07.25
В свете недавней статьи про этологию


8-1084032522
sashcan
2004-05-08 20:08
2004.07.25
Динамичек


1-1089299151
Andy BitOff
2004-07-08 19:05
2004.07.25
Мистика !!! Где утечка ???


9-1080912585
KA_
2004-04-02 17:29
2004.07.25
Сценарий игры - ругайте :)


1-1089223799
ZiRoCool
2004-07-07 22:09
2004.07.25
как НЕ главную форму отобразить в панели задач, в рантайме?