我有两个班级,Plant
和Generator
。 Generator
创建了一个向量,并通过notify()
监听Plant
进行广播。 classdef如下。请注意,我没有包含实际的数据生成方法,因为它对我的问题无关紧要。
classdef Plant < handle
properties
Listener
end
methods
function ListenerCallback(obj, data)
#% Perform an operation on data
end
end
end
classdef Generator < handle
properties
plant
end
events
newSignal
end
methods
function obj = Generator(plant)
obj.plant = plant;
obj.plant.Listener = addlistener(obj, 'newSignal', ...
@(src, data) obj.plant.ListenerCallback(data));
end
function delete(obj)
delete(obj.plant.Listener);
disp('Generator instance deleted');
end
end
end
我注意到Generator
析构函数的行为非常奇怪:我第一次创建然后删除Generator
实例,直到我第二次创建Generator
时才运行析构函数实例。这是一个例子:
>> P = Plant
P =
Plant handle
Properties:
Listener: []
Methods, Events, Superclasses
>> G = Generator(P)
G =
Generator handle
Properties:
plant: [1x1 Plant]
Methods, Events, Superclasses
>> clear G #% DESTRUCTOR NOT CALLED??
>> G = Generator(P)
Generator instance deleted #% why is the destructor run now?
G =
Generator handle
Properties:
plant: [1x1 Plant]
Methods, Events, Superclasses
>> clear G
Generator instance deleted #% and why is the destructor run properly now?
每次我的析构函数运行都非常重要。这里发生了什么,我怎样才能让析构函数正常运行? (我可能只是完全删除了侦听器,并直接从Plant.ListenerCallback()
实例调用Generator
,如果这不成功的话。)
编辑:看起来当我执行clear G
时,变量G
已从工作区中删除 - 但Generator
对象仍然存在于{{1}中}}。这就是没有调用析构函数的原因。所以我想删除P.Listener.Source
没有办法摆脱P.Listener
..有什么方法可以让我做我想做的事情,或者我只是被卡住了?
答案 0 :(得分:1)
为什么析构函数会在如此奇怪的时刻被调用?
clear G #% DESTRUCTOR NOT CALLED??
在G
P
的引用
G = Generator(P)
Generator instance deleted #% why is the destructor run now?
在实例化新Generator
时,侦听器会被覆盖。这会调用Generator
的第一个实例的析构函数,因为它不再引用它。
G =
Generator handle
Properties:
plant: [1x1 Plant]
Methods, Events, Superclasses
>> clear G
Generator instance deleted #% and why is the destructor run properly now?
让我们再看一下上一步中发生的事情:(1)plant
的听众被新的Generator
覆盖。 (2)这将调用第一个Generator
的析构函数。 (3)析构函数清除工作空间中plant
(!!!)(4)G
的监听器,现在是新Generator
的最后一个剩余实例。因此,clear G
调用类析构函数。
允许您使用clear
代替delete
的一种不太好的方法是重载clear
命令
function clear(varargin)
%# check for Generator objects
isGenerator = cellfun(@(x)evalin('caller','isa(x,''Generator'');'),varargin);
%# I loop here b/c I don't have the time to carefully construct
%# the evalin commands
%# Generator gets deleted, everybody else gets cleared
for i=1:nargin
if isGenerator(i)
evalin('caller',sprintf('delete %s',varargin{i}));
else
evalin('caller',sprintf('builtin(''clear'',''%s'');',varargin{i});
end
end
答案 1 :(得分:1)
也许我正在复活一个2岁的问题,但是......
Matlab希望清除析构函数;问题在于你如何定义你的听众。您将其定义为:
obj.plant.Listener = addlistener(obj, 'newSignal', ...
@(src, data) obj.plant.ListenerCallback(data));
这样做,您已经创建了一个匿名函数,该函数具有对obj的硬编码引用。当obj超出其他地方的范围时(例如,通过基础工作区中的清除),它仍然存在于您的匿名函数中。如果您改为定义:
obj.plant.Listener = addlistener(obj, 'newSignal', ...
@(src, data) src.plant.ListenerCallback(data));
匿名函数中没有硬编码引用。侦听器回调的第一个参数始终是从中调用的对象,但是您可以动态获取它,而不是在匿名函数中对对象引用进行硬编码。
希望这对你有一定价值!