MATLAB - 涉及计时器时不清除对象



这与这个问题有些关系,但不完全是。

我有两个班级,FunctionWrapperTimerWrapper

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

cleardelete之间的区别有点令人困惑(无论如何,对我来说(。如您所发现的,clear 不会显式调用析构函数。它只是从工作区中删除名称T所以T,以及它的基础计时器,在这一点上仍然存在。如果它们不包含对仍然存在的事物的引用,则 MATLAB 将正确删除T,包括调用其析构函数。实际上,由于计时器包含对 T 的引用(在其回调中(,该引用仍然存在,因此计时器(因此也T(不会被删除。

您可以使用 timerfindall 找到它(尽管工作区中没有名称(,如果您自己明确删除它,请使用

tmrs = timerfindall;
delete(tmrs);

你会发现T现在已经完全消失了。

不太确定这是一个错误,尽管我发现它非常令人困惑,并且cleardelete之间的区别可能会更好地记录下来。

至于解决方法,我不觉得明确调用delete是一个很大的痛苦,尽管如果您不小心打电话给clear,清理东西会更痛苦。我认为您链接到的线程的消息 #5 中的建议,而不是消息 #4,会更通用和健壮。

我认为您不应该按照@Amro链接到的单独线程中建议的方式重载clear:尽管如果您明确调用clear T,这可能会起作用,但如果您调用clear allclear variables,您仍然可能会遇到麻烦。(我刚才还没有尝试过,但我相信这些clear语法甚至不会遍历工作区中的内容并在每个内容上调用clear - 相反,它们调用内部 MATLAB 工作区对象的clear方法,这会很快变得混乱(。

这似乎是因为计时器的回调设置为非默认值。建议的解决方法(请参阅链接线程的消息 #4(是仅在调用 start 方法时设置回调函数,然后在调用 stop 方法时将其设置为 null。

最新更新