How to ensure that onCleanup destroys last
3 views (last 30 days)
I'd like to use onCleanup objects (among other things) to restore the initial matlabpath if the function terminates unexpectedly.
However, there is a problem with this: the execution order of onCleanup is uncertain, and it usually restores path before the destruction of some other created custom objects. As these custom objects depend on the modified path, they can't be properly destroyed with their delete() methods after onCleanup restores the initial path. In fact, onCleanup always seems to execute before the destruction of other objects (may be because it is also created first).
May be it is possible to create one large "restore environment" function, in which the order of destruction could be enforced, like it's advised in the Tips section of the function reference page ).
However, it would be nicer for me just to be able to ensure that onCleanup objects (or better one selected onCleanup object) are destroyed last when function terminates.
per isakson on 18 Mar 2023
Edited: per isakson on 2 Apr 2023
How to avoid this error?
Warning: The following error was caught while executing 'dlnode' class destructor: Method 'delete' is not defined for class 'dlnode' or is removed from MATLAB's search path.
The reason to this error is because the onCleanup object is destroyd before the dlnode object.
The documentation, "Handle Class Destructor", says
"[...] Do not assume that MATLAB destroys one value before another value when the same function contains multiple values."
I assume that onCleanup objects are treated the same way as any other values.
HandleClassDestructor_demo (below) demonstrates one way to "ensure that onCleanup objects are destroyed last when function terminates". However, "(or better one selected onCleanup object)" remains to be solved. The function, whos(*), which is used in the function, mco_names(), "lists in alphabetical order the names". Thus the names of the onCleanup objects may be used to control the order of their destruction. Two more comments: 1) I use evalin(), which I think is legitimate in this case. 2) On my local machine class definitions may reside in packages, but I failed to make that work here.
cup = onCleanup( @() fprintf(1,"and finally, destroy the onCleanup object\n") );
str = "abc";
mhc = [ MyHandleClass(1001), MyHandleClass(1002) ];
pkg = MyHandleClass(1003); % package.MyHandleClass(1003)
cellfun( @clearvars, mco_names )
Addendum: Then there is the requirement, "the function terminates unexpectedly", which isn't met. When I add return on the line before cellfun(@clearvars,mco_names) the demo outputs
and finally, destroy the onCleanup object
MyHandleClass/delete destroys object 1001
MyHandleClass/delete destroys object 1002
MyHandleClass/delete destroys object 1003
The solution above based on the function, mco_names(), is overdoing. The solution below is easier to remember and understand.
[~] = addpath( pth );
cup = onCleanup( @() rmpath( pth ) );
clearvars( '-except', 'cup' )