2016-07-18 140 views
12

Gli oggetti della classe di handle MATLAB sono deleted when they go out of scope. Ho oggetti che possono essere riutilizzati in diverse parti di un'applicazione, ma che voglio distruggere quando non vengono più utilizzati da nessuna parte. Il comportamento del ciclo di vita integrato di MATLAB mi consente di fare ciò senza mantenere alcun elenco globale aggiuntivo per tenere traccia di ciò che potrebbe utilizzare quell'oggetto.Trova la posizione in cui è archiviato l'handle nell'oggetto

però ho una situazione in cui un oggetto io penso dovuto andare fuori del campo di applicazione è ancora sparare callback del listener di eventi che vengono eliminati come parte del distruttore dell'oggetto. So dove penso che l'ultima maniglia di questo oggetto in esistenza avrebbe dovuto essere memorizzata, e abbastanza sicuro quando controllo che l'handle è stato cancellato. Quindi ci devono essere esempi di questo handle in ambito altrove.

La mia applicazione è una rete complessa di oggetti memorizzati come proprietà di altri oggetti. C'è qualcosa che posso fare per aiutare a rintracciare dove è stato memorizzato l'handle di questo oggetto?

Esempio

prima impostare una classe maniglia con un evento per ascoltare:

classdef Yard < handle 
    events 
     RollCall 
    end 
end 

Poi una classe maniglia che reagisce alle RollCall eventi da un oggetto Yard visualizzando un testo e poi notificare la sua proprio evento:

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 

E infine una classe che reagisce alle RollCall eventi da un Kennel oggetto mediante la visualizzazione del testo:

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 

Ora aggiungere alcune istanze di queste classi per l'area di lavoro:

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

Ora ho due Kennel oggetti di perimetro, con maniglie a cui fa riferimento nelle proprietà del Dog oggetti nell'array dogs. Chiamando notify(Y,'RollCall') produce il seguente 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 

Se l'originale due Dog s vengono eliminati poi canile 2 passa nell'ambito ma canile 1 rimane attiva in quanto è ancora riferimento il restante Dog:

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

Tuttavia, se nascondo un handle aggiuntivo al canile 1 da qualche altra parte prima di eliminare il rimanente Dog, rimarrà attivo:

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

La domanda è: se non so dove o quando è stato creato questo riferimento in più e perché non è stato eliminato, cosa posso fare per eseguire il debug l'esistenza dell'oggetto?

+0

Stai parlando esclusivamente di handle grafici? Se è così, questo potrebbe essere un buon punto di partenza: 'A = findall (0);' o 'B = findobj;'. –

+0

Hai provato a distruggere esplicitamente i tuoi oggetti invece di affidarti a MATLAB per farlo per te? Questa è una domanda che sarebbe ben servita da un [mcve]. – excaza

+0

@ Dev-iL - no, sto parlando esclusivamente di handle per oggetti di classi definite dall'utente, sfortunatamente. Un'analogia 'findall' per altri oggetti handle-class sarebbe l'ideale. – Will

risposta

1

Questo è qualcosa che ho affrontato molto. Vedete, la cancellazione della variabile dell'oggetto handle in un ambito non innescherà il distruttore se c'è ancora un riferimento all'oggetto in qualsiasi altro ambito.Se hai esplicitamente chiamato il distruttore per gli oggetti Dog e Kennel, il tuo oggetto timer avrà un riferimento a un oggetto non valido.

Nel costruttore per Dog è presente un listener di eventi creato, il cui distruttore non viene mai chiamato che conserva un riferimento a un'istanza di Dog.

Implementare una funzione di eliminazione per Dog e Kennel che ha chiamato la funzione di eliminazione per gli ascoltatori. Ecco uno schema di codifica che uso molto.

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 

Nell'esempio avete dato, è stato creato un oggetto timer che mantiene anche un riferimento al vostro dogs oggetto. La compensazione di dogs non elimina questo riferimento. Nessuno dei due avrebbe cancellato l'oggetto timer. È necessario eliminare esplicitamente gli oggetti timer.

Io uso handle oggetti molto, e di solito progettazione grafica 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 maniglia objects called in your code. I do this by setting the 'DeleteFcn'` callback sulla grafica maniglia oggetto che contiene l'interfaccia grafica (potrebbe essere una figura, uicontainer, uipanel, etc.). Includo questo esempio perché illustra con quanta attenzione devono essere mantenuti i riferimenti per gestire gli oggetti.

funzione 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 

fine

Un altro problema che ho notato con handle oggetti di classe, è che se si modifica e si salva il file di classdef mentre ci sono riferimenti vivi in ​​questi oggetti che puoi occasionalmente entrare in una situazione in cui ci sono riferimenti all'oggetto che puoi cancellare solo resettando Matlab.