cannot update class definition in Matlab

2019-02-14 13:10发布

I am running into an infuriating problem with Matlab, and an earlier answer to apparently the same problem didn't help me, unfortunately. I apologize that the question is rather long - you need quite a bit of information to reproduce the problem (I tried to trim it as much as I could...)

The problem is this: No matter what I do, after I have used a class I cannot "make Matlab forget". Values used seem to be persistent, and edits to the class definition won't "stick". In the latter case, the error message is:

Warning: The class file for 'myClass' has been changed; but the change cannot be applied because objects based on the old class file still exist. If you use those objects, you might get unexpected results. You can use the 'clear' command to remove those objects. See 'help clear' for information on how to remove those objects.

I get that message even after

>> clear all
>> clear functions
>> clear ans

Somehow the class definition is persistent despite my attempts to clear it. To make matters worse, when I modify a value of an instance of the class, then clear it, the value is somehow not "forgotten". To illustrate, here is the source code of myClass:

% a simple class definition that shows the problem that I cannot
% figure out how to redefine a class without restarting Matlab
classdef myClass < handle
    properties
        precursors = {'none'};
        numPre = {1};
        value = 1;
    end

    methods
        function obj = myClass(pre, num, val)
            % constructor
            if nargin > 0
                obj.precursors = pre;
                obj.numPre = num;
                obj.value = val;
            end
        end
        function v = sumVal(obj)
            % find the sum of the value of all precursors
            n = numel(obj.precursors);
            v = 0;
            for ii = 1:n
              pc = obj.precursors{ii};
              if isa(pc, 'myClass')
                  if ii==1
                      v = 0;
                  end
                  v = v + sumVal(pc) * obj.numPre{ii};
              else
                  v = obj.value;
              end
            end
        end
    end

    % only the following named instances may exist:
    enumeration
      grandpa   ({'none'},           {1},  1)
      father    ({myClass.grandpa},  {3}, -1)
      son       ({myClass.father},   {2}, -1) 
    end
end

In a fresh instance of Matlab, I do the following:

>> son = myClass.son;
>> sumVal(son)

ans = 

     6

>> grandpa = myClass.grandpa;
>> grandpa.value = 5;
>> sumVal(son)

ans =

    30

So far, so good. The sumVal function discovers the fathers and grandfathers, and the sumVal is computed correctly (6 * 1 in the first case, 6 * 5 in the second case).

Now I delete "everything" (I think):

>> clear all
>> clear functions
>> clear ans

And I create just one variable:

>> son = myClass.son;

Now comes the kicker - the unexpected answer

>> sumVal(son)

ans =

    30

When I inspect the variables loaded, I find

>> whos
Name    Size       Bytes  Class     Attributes

son      1x1         112  myClass

There is no grandpa instance, and the class definition file was not touched. Yet, the value of grandpa (which I created, then deleted) is somehow persistent.

And when I make a small change to the myClass.m file, and try to create a new variable (after a clear all), I get the message shown above. All of which leads me to my question:

Where is Matlab hiding an instance of my class so that variables are persistent after a clear all, and how do I clear the workspace (without restarting) so the class definition is "reset"?

I don't know if it matters, but I'm using Matlab 7.14.0.739 (R2012a)

2条回答
beautiful°
2楼-- · 2019-02-14 13:17

You have an intermediate instance myClass.father that is not being destroyed by MATLAB. You have to deleteit yourself

>> clear grandpa
>> delete(son.precursors{1})
>> clear son
>> clear classes
>> son = myClass.son
son = 
    son    
>> sumVal(son)
ans =
     6

Edit: Alternatively, you can add a destructor to your class

    function delete(obj)
        if isa(obj.precursors{1}, 'myClass')
            delete(obj.precursors{1});
        end
    end

and use delete(son) instead of leaving it to clear function to destroy. You can extend this to your case and recursively delete all instances in your tree.

查看更多
做个烂人
3楼-- · 2019-02-14 13:17

Those instances are "hiding" in the myClass enumeration class itself. Matlab is storing a reference to each of those named instances so when you reference them like myClass.father you get the same object back, instead of it constructing a new one. Probably similar to how values are stored in Constant properties on classes.

If you have any other classes that refer to the myClass.xxx enumerated instances in Constant properties, enumerations, or persistent variables, they could also be holding on to references to them.

Try doing clear classes a few times in a row instead of just once.

To help debug this, you could put a couple debugging printf() statements in the constructor and destructor for this class, so you can see when the instances are really created and cleaned up.

  function obj = myClass(pre, num, val)
      % constructor
      if nargin > 0
          obj.precursors = pre;
          obj.numPre = num;
          obj.value = val;
      end
      printf('myClass: created (%d, %d, nargin=%d)\n', obj.numPre, obj.value, nargin);
  end
  function delete(obj)
      printf('myClass: deleting (%d, %d)\n', obj.numPre, obj.value);
  end
查看更多
登录 后发表回答