这与这个问题有些关系,但不完全是。
我有两个班级,FunctionWrapper
和TimerWrapper
:
classdef FunctionWrapper < handle
methods
function Fcn(obj)
disp('FunctionWrapper.Fcn was called!');
end
end
end
classdef TimerWrapper < handle
properties
Timer
end
methods
function obj = TimerWrapper(other_object)
obj.Timer = timer;
set(obj.Timer, 'Period', 1);
set(obj.Timer, 'ExecutionMode', 'fixedSpacing');
set(obj.Timer, 'TimerFcn', @(event, data) other_object.Fcn);
end
function start(obj)
start(obj.Timer);
end
function stop(obj)
stop(obj.Timer);
end
function delete(obj)
disp('destructor called!');
delete(obj.Timer);
end
end
end
假设我在命令窗口中执行以下代码:
>> F = FunctionWrapper;
>> T = TimerWrapper(F);
>> clear T %# T's destructor not called
>> timerfind %# just to verify that no, the destructor was never called
Timer Object: timer-1
Timer Settings
ExecutionMode: fixedSpacing
Period: 1
BusyMode: drop
Running: off
Callbacks
TimerFcn: @(event,data)other_object.Fcn
ErrorFcn: ''
StartFcn: ''
StopFcn: ''
这是怎么回事?我知道timer
对象需要手动删除,但我认为这将在析构函数中处理 TimerWrapper
.如果不使用 Amro 丑陋但简单的解决方法来重载 clear
命令,有没有办法从工作区clear T
?此外,没有任何东西指的是T
,那么为什么存在对它的引用呢?(从未调用析构函数的事实暗示了这一事实。这是否埋藏在计时器对象本身中?
如果键入 t = TimerWrapper; f = functions(t.Timer.TimerFcn); f.workspace(2)
,您将看到用于回调的匿名函数的工作区包含对TimerWrapper
对象本身的引用。所以那里有一种循环引用,clear
没有拾取。
给定设置方式,可以通过显式调用析构函数然后调用 clear
来删除T
(及其基础计时器对象(。
T.delete
clear T
clear
和delete
之间的区别有点令人困惑(无论如何,对我来说(。如您所发现的,clear
不会显式调用析构函数。它只是从工作区中删除名称T
。所以T
,以及它的基础计时器,在这一点上仍然存在。如果它们不包含对仍然存在的事物的引用,则 MATLAB 将正确删除T
,包括调用其析构函数。实际上,由于计时器包含对 T
的引用(在其回调中(,该引用仍然存在,因此计时器(因此也T
(不会被删除。
您可以使用 timerfindall
找到它(尽管工作区中没有名称(,如果您自己明确删除它,请使用
tmrs = timerfindall;
delete(tmrs);
你会发现T
现在已经完全消失了。
不太确定这是一个错误,尽管我发现它非常令人困惑,并且clear
和delete
之间的区别可能会更好地记录下来。
至于解决方法,我不觉得明确调用delete
是一个很大的痛苦,尽管如果您不小心打电话给clear
,清理东西会更痛苦。我认为您链接到的线程的消息 #5 中的建议,而不是消息 #4,会更通用和健壮。
我认为您不应该按照@Amro链接到的单独线程中建议的方式重载clear
:尽管如果您明确调用clear T
,这可能会起作用,但如果您调用clear all
或clear variables
,您仍然可能会遇到麻烦。(我刚才还没有尝试过,但我相信这些clear
语法甚至不会遍历工作区中的内容并在每个内容上调用clear
- 相反,它们调用内部 MATLAB 工作区对象的clear
方法,这会很快变得混乱(。
这似乎是因为计时器的回调设置为非默认值。建议的解决方法(请参阅链接线程的消息 #4(是仅在调用 start
方法时设置回调函数,然后在调用 stop
方法时将其设置为 null。