2014-12-09 14 views
1

TForm의 _release 메서드가 소멸자를 호출하지 않는 이유는 무엇입니까?TForm의 _release가 소멸자를 호출하지 않는 이유는 무엇입니까?

function TInterfacedObject._Release: Integer; 
begin 
    Result := InterlockedDecrement(FRefCount); 
    if Result = 0 then 
    Destroy; 
end; 

function TComponent._Release: Integer; 
begin 
    if FVCLComObject = nil then 
    Result := -1 // -1 indicates no reference counting is taking place 
    else 
    Result := IVCLComObject(FVCLComObject)._Release; 
end; 

의 TInterfacedObject의 _release이 매우 이해할 것 같지만 TComponent의의 _release이하는 일 :

var 
    F, U : IUnknown; 

procedure TForm1.btn1Click(Sender: TObject); 
begin 
    U := IUnknown(TMyObject.Create); // MyIterfacedObject (inherits TInterfacedObject) 
    F := IUnknown(TMyForm.Create(nil)); 
end; 

procedure TForm1.btn2Click(Sender: TObject); 
begin 
    U := nil; // Calls destructor 
    F._Release; // Does not call destructor 
    F := nil; // Does not call destructor 
end; 

나는 TInterfaceObject 및 TComponent의 클래스의 _release 방법을 살펴했다? 이상하게 보입니다 ...

답변

3

그 이유는 TComponent은 평생 관리가 클래스 사용자의 책임이라는 취지의 정책을 채택하고 있으며 취해진 인터페이스 참조에 의해 자동으로 관리되지 않기 때문입니다. 이 정책은 TComponent._Release에 명확하게 표시됩니다.

function TComponent._Release: Integer; 
begin 
    if FVCLComObject = nil then 
    Result := -1 // -1 indicates no reference counting is taking place 
    else 
    Result := IVCLComObject(FVCLComObject)._Release; 
end; 

일반적인 시나리오, 당신이 설명 하나, nil 동일 FVCLComObject있다. 따라서 코드에는 -1을 반환하여 참조 카운팅이 없다고 명시 적으로 표시됩니다. 심지어 그런 방식으로 주석을 달았습니다.

평생 관리는 어떤 방식 으로든 수행되어야합니다. 델파이 코드와 두 일반적으로 사용되는 패턴은 다음과 같습니다 TComponent가 종종 생성자 소유자 구성 요소를 전달하는 것이이 다르게 조금의 사용

var 
    obj: TMyObject; 
.... 
obj := TMyObject.Create; 
try 
    DoSomething(obj); 
finally 
    obj.Free; // the object is explicitly destroyed here 
end; 

,하지만

수명은 발신자에 의해 관리. 그리고 나서이 주인은 소유 된 구성 요소를 파괴 할 책임이 있습니다. 그래서 패턴은 다음과 같습니다 : 인터페이스에 의해 관리

component := TMyComponent.Create(OwnerComponent); 
... // now component will be destroyed when OwnerComponent is destroyed 

수명은

var 
    intf: IMyInterface; 
.... 
intf := TMyObject.Create; 
DoSomething(intf); 
// the implementing object behind intf is destroyed when the last 
// interface reference leaves scope 

당신은이 패턴을 혼합 할 수 없습니다 참조합니다. TComponent이 첫 번째 패턴을 따를 것이라는 디자인이 선택되었습니다. 따라서 인터페이스 참조 카운팅을 비활성화해야합니다. 대조적으로 TInterfacedObject은 다른 정책을 채택합니다.

+0

두 가지 일반적으로 사용되는 패턴 외에도 소유자 패턴을 언급해야한다고 생각합니다. 특히 OP가 무엇을 의미하는지 TComponent에서 사용되기 때문입니다. – iamjoosy

+0

답을 다시 읽었을 때 TComponent는 첫 번째 예제 (TMyObject를 사용)에서 패턴을 따르지 않지만 할 수는 있지만 TComponent 자손의 상속 패턴은 소유권 모델이라고합니다. – iamjoosy

+0

@iamjoosy '소유자'로 전달되는 내용에 따라 다릅니다. 'nil '을 건네면 호출자는 소유자로 남아 있습니다. 'nil '이외의 것을 전달하면 다른 것이 소유자가됩니다. 근본적으로 같은 것입니다. –