首先是问题:为什么删除const UnregisterNode()导致失败,而不是导致失败RegisterNode().
现在的背景:我正在使用Interfaces在Delphi XE中工作,我遇到了一个让我停顿一下的工件,我得出的结论是我真的不明白为什么.
不需要显式释放作为接口访问的对象.当最后一个引用超出范围时,它将被销毁.这似乎很简单.我编写了一个测试用例来显示按预期运行的变量和两个失败的变量.六个测试用例仅限于Register和Unregister方法的Node参数的变体.
按下表单上的单个按钮可创建容器和三个节点.对它们进行操作以演示该程序
该程序创建一些链接到简单容器的简单节点.问题发生在案例#1和#6中.在释放节点时,它会调用containers Unregister()方法.该方法删除指向TList中节点的指针的副本.当在两个失败的情况下离开该方法时,它以Destroy()递归方式再次启动该过程调用该节点的方法,直到发生堆栈溢出.
在有效的四种情况下,Destroy()方法恢复正常,程序将继续正常退出.
失败#1(案例1)
procedure RegisterNode(Node:INode);
procedure UnregisterNode(Node:INode);
Run Code Online (Sandbox Code Playgroud)
Unregister()从TNode.Destroy()方法调用节点似乎影响INode的引用计数导致多次调用Destroy(). 为什么这种情况发生我不明白.当我Register()具有相同样式的参数的节点时,它不会发生.
失败#2(案例6)
procedure RegisterNode(const Node:INode);
procedure UnregisterNode(Node:INode);
Run Code Online (Sandbox Code Playgroud)
这里发生了同样的失败模式.如案例5中那样将const添加到参数列表可防止递归调用Destroy().
代码:
unit fMain;
{
Case 1 - Fails when a node is freed, after unregistering,
TNode.Destroy is called again
Case 2 - Passes
case 3 - Passes
Case 4 - Passes
Case 5 - Passes
Case 6 - Fails the …Run Code Online (Sandbox Code Playgroud) 注意Exit内联函数中的命令用法!我一直在这里使用Delphi XE3.
在某些情况下,当呼叫到包含一个内联函数取得Exit命令,并返回值的内联函数的用于直接在WriteLn(),编译器报告的错误消息,
"dcc"退出代码1.
甚至最糟糕的是,Delphi IDE在没有任何确认的情况下终止.
function ProcessNumber(const iNumber: Integer): Boolean; inline;
begin
if iNumber = 0 then begin
Result := False;
Exit;
end;
// some code here ...
Result := True;
end;
procedure Test;
begin
writeln( ProcessNumber(0) );
end;
begin
Test;
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)
但是,如果内联函数的返回值存储在变量中,然后使用该变量WriteLn(),则不会发生该问题.
procedure Test;
var
b: Boolean;
begin
b := ProcessNumber(0);
writeln(b);
end;
Run Code Online (Sandbox Code Playgroud)