2012-03-04 22 views
2

我有兩個類,PlantGeneratorGenerator創建一個矢量並通過notify()播放它,其中Plant監聽。下面的classdefs。請注意,我沒有包含實際的數據生成方法,因爲這與我的問題無關。MATLAB - 對象析構函數在涉及偵聽器時不運行

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對象依然存在於P.Listener.Source中。這就是爲什麼析構函數沒有被調用。所以我想沒有辦法擺脫P.Listener刪除G ..有什麼辦法讓這個做我想做的或者我只是卡住了嗎?

+0

嘗試'刪除G;清除G'而不是'只清除G'?從文檔中,「您可以清除圖形或其他對象的句柄,但不會刪除對象本身,使用delete刪除對象和文件。刪除對象不會刪除變量(如果有的話)用於存儲它處理。」 – tmpearce 2012-03-05 01:04:43

+0

@tmpearce - 確實有效。我只希望使用'clear G',因爲這個代碼是一個更大的代碼庫的一部分。我使用MATLAB的大多數人都不知道'delete'和'clear'有什麼區別,所以這可能會讓人感到困惑。 – 2012-03-05 01:13:55

+0

是的,我明白了。你可能想用這個信息來更新你的問題,因爲它不是析構函數的問題,而是對象上的'clear'。 – tmpearce 2012-03-05 01:25:32

回答

1

爲什麼在這樣怪異的時間調用析構函數?

clear G #% DESTRUCTOR NOT CALLED?? 

還有的P

G = Generator(P) 
Generator instance deleted #% why is the destructor run now? 

由於新Generator被實例化G參考的監聽器,監聽器被覆蓋。這將調用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 
+0

很好的解釋。醜陋但直接的解決方法。一如既往地感謝,先生。 – 2012-03-05 07:06:20

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)); 

在匿名函數中沒有硬編碼引用。偵聽器回調的第一個參數始終是它被調用的對象,但是您可以實時獲取它,而不是在匿名函數中硬編碼對象引用。

希望這對你仍然有一定的價值!

相關問題