查找范围中存储句柄的位置 [英] Find where handle is stored in scope

查看:64
本文介绍了查找范围中存储句柄的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MATLAB句柄类对象在超出范围时被删除.我有可以在应用程序的不同部分中重用的对象,但是当它们不再在任何地方使用时,我想销毁这些对象. MATLAB的内置生命周期行为使我能够执行此操作,而无需维护任何其他全局列表来跟踪使用该对象的可能情况.

MATLAB handle class objects are deleted when they go out of scope. I have objects that can be reused in different parts of an application, but which I want to destroy when they are no longer used anywhere. MATLAB's built in lifecycle behaviour allows me to do this without maintaining any additional global list to keep track of what might be using that object.

但是,我有一种情况,我认为应该超出范围,但仍然触发事件侦听器回调,这些回调作为对象的析构函数的一部分被删除.我知道我认为该对象存在的最后一个句柄应该存储在什么地方,当我检查那里的句柄已被清除时,可以肯定的.因此,在其他地方的范围内一定有此句柄的实例.

However I have a situation where an object I think should have gone out of scope is still firing event listener callbacks that are deleted as part of the object's destructor. I know where I think the last handle to this object in existence should have been stored, and sure enough when I check there that handle has been cleared. So there must be instances of this handle in scope somewhere else.

我的应用程序是一个复杂的对象网络,这些对象存储为其他对象的属性.我有什么办法可以帮助您找到该对象的句柄存储在范围内的什么地方?

My application is a complex network of objects stored as properties of other objects. Is there anything I can do to help track down where in scope the handle to this object is being stored?

首先设置一个带有事件的句柄类以监听:

First set up a handle class with an event to listen to:

classdef Yard < handle
    events
        RollCall
    end
end

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

Then a handle class that reacts to RollCall events from a Yard object by displaying some text and then notifying its own event:

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

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

And finally a class that reacts to RollCall events from a Kennel object by displaying some text:

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

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

Now add some instances of these classes to the workspace:

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对象,这些句柄在数组dogsDog对象的属性中引用.调用notify(Y,'RollCall')会产生以下输出:

I now have two Kennel objects in scope, with handles referenced in the properties of the Dog objects in the array dogs. Calling notify(Y,'RollCall') produces the following output:

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仍引用该狗窝:

If the original two Dogs are deleted then kennel 2 goes out of scope but kennel 1 remains active since it is still referenced by the remaining Dog:

>> dogs = dogs(3);
>> notify(Y,'RollCall')

Kennel 1 is in the yard
Rover is in kennel 1

但是,如果我在删除其余的Dog之前在范围内其他地方隐藏了第1个狗窝的附加句柄,则它将保持活动状态:

However if I hide an additional handle to kennel 1 somewhere else in scope before deleting the remaining Dog then it will remain active:

>> t = timer('UserData',dogs(1).kennel);
>> clear dogs
>> notify(Y,'RollCall')

Kennel 1 is in the yard

问题是,如果我不知道在哪里或何时创建此额外引用,为什么不删除它,我该怎么做才能调试对象的存在?

The question is if I don't know where or when this extra reference was created and why it hasn't been deleted, what can I do to debug the existence of the object?

推荐答案

这是我已经处理的很多事情.您会看到,如果在任何其他作用域中仍然有对对象的引用,则清除一个作用域中的handle对象变量不会触发析构函数.如果您显式调用了DogKennel对象的析构函数,则您的计时器对象将具有对无效对象的引用.

This is something I have dealt with a lot. You see, clearing the handle object variable in one scope will not trigger the destructor if there is still a reference to the object in any other scope. If you explicitly called the destructor for the Dog and Kennel objects, your timer object would have a reference to an invalid object.

Dog的构造函数中,创建了一个事件侦听器,该事件侦听器从未调用过,它保留了对Dog实例的引用.

In the constructor for Dog there is an event listener created, whose destructor is never called which retains a reference to an instance of Dog.

我将为DogKennel实现删除功能, 侦听器的删除功能.这是我经常使用的编码模式.

I would implement a delete function for Dog and Kennel which called the delete function for the listeners. Here is a coding pattern I use a lot.

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对象.

In the example you gave, you created a timer object which also maintains a reference to your dogs object. Clearing dogs does not eliminate this reference. Neither would clearing the timer object. You must explicitly delete timer objects.

我经常使用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 handle objects called in your code. I do this by setting the'DeleteFcn'`回调(可以是图形,uicontainer,uipanel等). .我之所以包含此示例,是因为它说明了如何谨慎维护对处理对象的引用.

I use handle objects a lot, and usually design GUIs 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 anyhandleobjects called in your code. I do this by setting the'DeleteFcn'` callback on the graphics handle object that contains the GUI (could be a figure, uicontainer, uipanel, etc.). I include this example because it illustrates how carefully references to handle objects need to be maintained.

函数dispGUI(handleOBJ,hg)

function 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来清除.

Another issue I have noticed with handle class objects, is that if you modify and save their classdef file while there are live references to these objects you can occasionally get into a situation where there are references to the object that you can only clear by resetting Matlab.

这篇关于查找范围中存储句柄的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆