Форум: "Потрепаться";
Поиск по всему сайту: www.delphimaster.net;
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];




Вниз

Особенности вызовов конструкторов 


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]

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


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

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




Форум: "Потрепаться";
Поиск по всему сайту: www.delphimaster.net;
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.77 MB
Время: 0.122 c
14-1088686545     WondeRu               2004-07-01 16:55  2004.07.25  
Годовщина!


1-1089725392      Newuser               2004-07-13 17:29  2004.07.25  
Разрешение экрана


1-1089711127      Kost                  2004-07-13 13:32  2004.07.25  
Сложное наследование


6-1085245111      Игорь Н.              2004-05-22 20:58  2004.07.25  
Как обратится к web странице не используя Internet Explorer


1-1089705911      half_litre            2004-07-13 12:05  2004.07.25  
Hint в формах из dll