Delphi - 智能指针构造函数的奇怪行为
Delphi - Strange behavior with smart pointer constructors
我正在处理一个包含多个包的项目。在我的一个基础包中,我声明了一个智能指针,就像那样(这里是完整的代码):
unit UTWSmartPointer;
interface
type
IWSmartPointer<T> = reference to function: T;
TWSmartPointer<T: class, constructor> = class(TInterfacedObject, IWSmartPointer<T>)
private
m_pInstance: T;
public
constructor Create; overload; virtual;
constructor Create(pInstance: T); overload; virtual;
destructor Destroy; override;
function Invoke: T; virtual;
end;
implementation
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create;
begin
inherited Create;
m_pInstance := T.Create;
end;
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create(pInstance: T);
begin
inherited Create;
m_pInstance := pInstance;
end;
//---------------------------------------------------------------------------
destructor TWSmartPointer<T>.Destroy;
begin
m_pInstance.Free;
m_pInstance := nil;
inherited Destroy;
end;
//---------------------------------------------------------------------------
function TWSmartPointer<T>.Invoke: T;
begin
Result := m_pInstance;
end;
//---------------------------------------------------------------------------
end.
稍后在我的项目中(以及在另一个包中),我将此智能指针与 GDI+ 对象(TGpGraphicsPath)一起使用。我这样声明图形路径:
...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create();
...
但是,当我执行代码时,屏幕上没有绘制任何东西。我没有收到任何错误、异常或访问冲突,只是一个空白页面。但是,如果我只是这样更改我的代码:
...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create(TGpGraphicsPath.Create);
...
然后一切都变好了,我的路径完全按照预期绘制。但是我不明白为什么第一个构造函数没有按预期工作。有人可以向我解释这种奇怪的行为吗?
此致
你掉进了一个相当复杂的陷阱。当你写:
TGpGraphicsPath.Create
您可能认为您正在调用无参数构造函数。但事实并非如此。您实际上是在调用此构造函数:
constructor Create(fillMode: TFillMode = FillModeAlternate); reintroduce; overload;
您没有提供参数,因此默认值由编译器提供。
在你的智能指针 class 你写:
T.Create
这真的是在调用无参数构造函数。但那是TObject
定义的构造函数。使用该构造函数时,TGPGraphicsPath
实例未正确初始化。
如果要使用 constructor
泛型约束,还必须确保始终使用可以使用无参数构造函数正确构造的 class。不幸的是,TGPGraphicsPath
不符合要求。确实有很多这样的 classes。
在此处您可以做很多事情来避免显式调用构造函数。对于这个特定的 class,您的智能指针 class 几乎不可能计算出要调用哪个构造函数。
我的建议是避开 constructor
通用约束并强制智能指针的使用者 class 显式实例化实例。
这是一个很常见的问题——不到一周前我在这里回答了一个类似的问题:
我正在处理一个包含多个包的项目。在我的一个基础包中,我声明了一个智能指针,就像那样(这里是完整的代码):
unit UTWSmartPointer;
interface
type
IWSmartPointer<T> = reference to function: T;
TWSmartPointer<T: class, constructor> = class(TInterfacedObject, IWSmartPointer<T>)
private
m_pInstance: T;
public
constructor Create; overload; virtual;
constructor Create(pInstance: T); overload; virtual;
destructor Destroy; override;
function Invoke: T; virtual;
end;
implementation
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create;
begin
inherited Create;
m_pInstance := T.Create;
end;
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create(pInstance: T);
begin
inherited Create;
m_pInstance := pInstance;
end;
//---------------------------------------------------------------------------
destructor TWSmartPointer<T>.Destroy;
begin
m_pInstance.Free;
m_pInstance := nil;
inherited Destroy;
end;
//---------------------------------------------------------------------------
function TWSmartPointer<T>.Invoke: T;
begin
Result := m_pInstance;
end;
//---------------------------------------------------------------------------
end.
稍后在我的项目中(以及在另一个包中),我将此智能指针与 GDI+ 对象(TGpGraphicsPath)一起使用。我这样声明图形路径:
...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create();
...
但是,当我执行代码时,屏幕上没有绘制任何东西。我没有收到任何错误、异常或访问冲突,只是一个空白页面。但是,如果我只是这样更改我的代码:
...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create(TGpGraphicsPath.Create);
...
然后一切都变好了,我的路径完全按照预期绘制。但是我不明白为什么第一个构造函数没有按预期工作。有人可以向我解释这种奇怪的行为吗?
此致
你掉进了一个相当复杂的陷阱。当你写:
TGpGraphicsPath.Create
您可能认为您正在调用无参数构造函数。但事实并非如此。您实际上是在调用此构造函数:
constructor Create(fillMode: TFillMode = FillModeAlternate); reintroduce; overload;
您没有提供参数,因此默认值由编译器提供。
在你的智能指针 class 你写:
T.Create
这真的是在调用无参数构造函数。但那是TObject
定义的构造函数。使用该构造函数时,TGPGraphicsPath
实例未正确初始化。
如果要使用 constructor
泛型约束,还必须确保始终使用可以使用无参数构造函数正确构造的 class。不幸的是,TGPGraphicsPath
不符合要求。确实有很多这样的 classes。
在此处您可以做很多事情来避免显式调用构造函数。对于这个特定的 class,您的智能指针 class 几乎不可能计算出要调用哪个构造函数。
我的建议是避开 constructor
通用约束并强制智能指针的使用者 class 显式实例化实例。
这是一个很常见的问题——不到一周前我在这里回答了一个类似的问题: