查找范围

时间:2016-07-18 09:19:15

标签: matlab oop

MATLAB句柄类对象是deleted when they go out of scope。我有可以在应用程序的不同部分重用的对象,但是当它们不再在任何地方使用时我想破坏它们。 MATLAB内置的生命周期行为允许我在不维护任何其他全局列表的情况下执行此操作,以跟踪可能正在使用该对象的内容。

但是我遇到的情况是,我认为的对象应该超出范围仍然会触发作为对象析构函数的一部分被删除的事件侦听器回调。我知道我认为存在的这个对象的最后一个句柄应该已经存储,当我检查那个句柄已经被清除时。所以在其他地方必须有这个句柄的实例。

我的应用程序是一个复杂的对象网络,存储为其他对象的属性。我有什么办法可以帮助追踪存储此对象句柄的范围吗?

实施例

首先设置一个句柄类,其中包含要监听的事件:

classdef Yard < handle
    events
        RollCall
    end
end

然后是一个句柄类,它通过显示一些文本然后通知它自己的事件来响应来自RollCall对象的Yard个事件:

classdef Kennel < handle
    properties
        id
        yardListener
    end

    events
        RollCall
    end

    methods
        function obj = Kennel(yard,id)
            obj.yardListener = event.listener(yard,'RollCall',@obj.Report);
            obj.id = id;
        end

        function Report(obj,~,~)
            fprintf('Kennel %d is in the yard\n', obj.id);
            notify(obj,'RollCall');
        end
    end
end

最后一个类通过显示一些文本来响应来自RollCall对象的Kennel个事件:

classdef Dog
    properties
        name
        kennel
        kennelListener
    end

    methods
        function obj = Dog(name,kennel)
            obj.name = name;
            obj.kennel = kennel;
            obj.kennelListener = event.listener(kennel,'RollCall',@obj.Report);
        end

        function Report(obj,kennel,~)
            fprintf('%s is in kennel %d\n', obj.name, kennel.id);
        end
    end 
end

现在将这些类的一些实例添加到工作区:

Y = Yard;
% Construct two Dog objects, in each case constructing a new Kennel object to pass to the constructor
dogs = [Dog('Fido',Kennel(Y,1)) Dog('Rex',Kennel(Y,2))];
% Construct a third Dog, reusing the Kennel object assigned to dog(1)
dogs(3) = Dog('Rover',dogs(1).kennel);

我现在在范围内有两个Kennel个对象,在数组Dog中的dogs个对象的属性中引用了句柄。调用notify(Y,'RollCall')会产生以下输出:

Kennel 2 is in the yard
Rex is in kennel 2
Kennel 1 is in the yard
Rover is in kennel 1
Fido is in kennel 1

如果原始的两个Dog被删除,那么狗舍2就会超出范围,但是狗舍1仍然有效,因为它仍被剩余的Dog引用:

>> dogs = dogs(3);
>> notify(Y,'RollCall')
Kennel 1 is in the yard
Rover is in kennel 1

但是,如果我在删除剩余的Dog之前在范围内的其他位置隐藏了一个额外的句柄,那么它将保持活动状态:

>> t = timer('UserData',dogs(1).kennel);
>> clear dogs
>> notify(Y,'RollCall')
Kennel 1 is in the yard

问题是,如果我不知道创建这个额外引用的位置和时间以及为什么没有删除它,我该怎么做来调试对象的存在?

1 个答案:

答案 0 :(得分:1)

这是我经常处理的事情。您会看到,如果在任何其他范围内仍然存在对该对象的引用,则清除一个范围中的句柄对象变量将不会触发析构函数。如果您为DogKennel对象显式调用了析构函数,那么您的计时器对象将具有对无效对象的引用。

Dog的构造函数中,创建了一个事件侦听器,从不调用其析构函数,该析构函数保留对Dog实例的引用。

我会为调用的DogKennel实现删除功能 监听器的删除功能。这是我经常使用的编码模式。

classdef MyClass < handle
   properties 
      listener % listeners are themselves handle objects
   end
   methods
      %% Class constructor creates a listener 
      %% Class methods
      function delete(obj)
         % do this for all handle object properties
         % Also, avoid calling constructors for handle objects in
         % the properties block. That can create references to handle
         % objects which can only be cleared by a restart
         if ishandle(obj.listener)
            delete(obj.listener)
         end
      end
   end
end

在您给出的示例中,您创建了一个timer对象,该对象还维护对dogs对象的引用。清除dogs并不能消除此引用。也不会清除timer对象。您必须明确删除timer个对象。

我经常使用handle个对象,并且通常在包含GUI的图形句柄对象上设计GUI s to go with them (aside, never, never, never use GUIDE for this. It is the worst thing ever). You have to be sure to clear all references to any句柄objects called in your code. I do this by setting the&#39; DeleteFcn&#39;`回调是一个人物,uicontainer,uipanel等)。我包含这个例子,因为它说明了需要如何仔细地维护对句柄对象的引用。

函数dispGUI(handleOBJ,hg)

  %% build gui in hg
  set(hg,'DeleteFcn',@deleteCallBack)
  h  = uicontrol(hg,'Callback',@myCallback)
  function myCallback(h,varargin)
     % So now there is a reference to handleOBJ
     % It will persist forever, even if cleared in the caller's
     % workspace, thus we clear it when the containing graphics 
     % object delete callback is triggered.
     if isvalid(handleOBJ)
        set(h,'string','valid')
     else
        set(h,'string','invalid')
     end
  end


  function deleteCallBack(varargin)
     % calling clear on handleOBJ clears it from the scope of the 
     % GUI function
     % also call clear on the containing function
     clear handleOBJ
     clear(mfilename)
  end

我注意到handle类对象的另一个问题是,如果你修改并保存他们的classdef文件,而对这些对象有实时引用,你偶尔会遇到有引用的情况只能通过重置Matlab来清除对象。