Очистка после завершения выполнения функции

Обзор

Хорошая методика программирования состоит в том, чтобы убедиться, что вы оставляете окружение программы в чистом состоянии, которое не мешает никакому другому программному коду. Для примера, вы можете захотеть

  • Закройте все файлы, которые вы открыли для импорта или экспорта.

  • Восстановите MATLAB® путь.

  • Блокируйте или разблокируйте память, чтобы предотвратить или разрешить удаление функции MATLAB или файлов MEX.

  • Если рабочая папка изменена, установите ее значение по умолчанию.

  • Убедитесь, что глобальные и постоянные переменные находятся в правильном состоянии.

MATLAB обеспечивает onCleanup функция для этой цели. Эта функция, при использовании в любой программе, устанавливает стандартную программу очистки для этой функции. Когда функция завершается, как обычно, так и в случае ошибки или Ctrl+C, MATLAB автоматически выполняет стандартную программу очистки.

Следующий оператор устанавливает стандартную программу очистки cleanupFun для текущей выполняемой программы:

cleanupObj = onCleanup(@cleanupFun);

Когда ваша программа выходит, MATLAB находит любые образцы onCleanup Класс и выполняет связанные указатели на функцию. Процесс генерации и активации очистки функции включает следующие шаги:

  1. Написание одной или нескольких стандартных программ очистки для разрабатываемой программы. Предположим, что сейчас требуется только одна такая стандартная программа.

  2. Создайте указатель на функцию для стандартной программы очистки.

  3. В какой-то момент, обычно в начале вашего программного кода, вставьте вызов onCleanup функция, передающая указатель на функцию.

  4. Когда программа запускается, вызов на onCleanup создает объект очистки, который содержит указатель на стандартную программу очистки, созданную на шаге 1.

  5. Когда программа заканчивается, MATLAB неявно очищает все объекты, которые являются локальными переменными. Это вызывает метод деструктора для каждого локального объекта в вашей программе, включая объект очистки, созданный на шаге 4.

  6. Метод деструктора для этого объекта вызывает эту стандартную программу, если она существует. Это выполняет задачи, необходимые для восстановления окружения программирования.

Можно объявить любое количество стандартных программ очистки для программного файла. Каждый вызов на onCleanup устанавливает отдельную стандартную программу очистки для каждого возвращенного объекта очистки.

Если по какой-либо причине объект вернулся onCleanup сохраняется за пределами жизни вашей программы, тогда стандартная программа очистки, связанная с этим объектом, не запускается, когда ваша функция прекращает работать. Вместо этого он будет запускаться каждый раз, когда объект будет уничтожен (например, путем очистки переменной объекта).

Ваша стандартная программа очистки никогда не должна полагаться на переменные, которые определены вне этой стандартной программы. Например, вложенная функция, показанная здесь слева, выполняется без ошибок, в то время как очень аналогичная функция справа терпит неудачу с ошибкой Undefined function or variable 'k'. Это происходит из-за зависимости стандартной программы очистки от переменной k который определяется вне вложенной стандартной программы очистки:

function testCleanup               function testCleanup
k = 3;                             k = 3;
myFun                              obj = onCleanup(@myFun);
    function myFun                     function myFun
    fprintf('k is %d\n', k)            fprintf('k is %d\n', k)
    end                                end
end                                end

Примеры очистки программы при выходе

Пример 1 - Закрыть открытые файлы на выходе

MATLAB закрывает файл с идентификатором fid когда функция openFileSafely завершает:

function openFileSafely(fileName)
fid = fopen(fileName, 'r');
c = onCleanup(@()fclose(fid));

s = fread(fid);
     .
     .
     .
end

Пример 2 - Ведение выбранной папки

Этот пример сохраняет текущую папку, functionThatMayError возвращает ошибку или нет:

function changeFolderSafely(fileName)
   currentFolder = pwd;
   c = onCleanup(@()cd(currentFolder));

   functionThatMayError;
   end   % c executes cd(currentFolder) here.

Пример 3 - Закройте фигуру и восстановите путь MATLAB

Этот пример расширяет путь MATLAB, чтобы включить файлы в папки toolbox\images, а затем отображает рисунок из одной из этих папок. После отображения рисунка стандартная программа очистки restore_env закрывает рисунок и восстанавливает путь в исходном состоянии.

function showImageOutsidePath(imageFile)
fig1 = figure;
imgpath = genpath([matlabroot '\toolbox\images']);

% Define the cleanup routine.
cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

% Modify the path to gain access to the image file, 
% and display the image.
addpath(imgpath);
rgb = imread(imageFile);
fprintf('\n   Opening the figure %s\n', imageFile);
image(rgb);
pause(2);

   % This is the cleanup routine.
   function restore_env(fighandle, newpath)
   disp '   Closing the figure'
   close(fighandle);
   pause(2)
   
   disp '   Restoring the path'
   rmpath(newpath);
   end
end

Запустите функцию как показано здесь. Можно проверить, что путь был восстановлен, сравнив длину пути до и после запуска функции:

origLen = length(path);

showImageOutsidePath('greens.jpg')
   Opening the figure greens.jpg
   Closing the figure
   Restoring the path

currLen = length(path);
currLen == origLen
ans =
     1

Получение информации о стандартной программе очистки

В примере 3, показанном выше, стандартная программа очистки и данные, необходимые для ее вызова, содержатся в указателе анонимной функции:

@()restore_env(fig1, imgpath)

Детали этого указателя затем содержатся в объекте, возвращенном onCleanup функция:

cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

Получить доступ к этим данным можно используя task свойство объекта очистки, как показано здесь. (Измените showImageOutsidePath функция путем добавления следующего кода непосредственно перед строкой с комментариями, которая говорит "% This is the cleanup routine.”)

disp '   Displaying information from the function handle:'
task = cleanupObj.task;
fun = functions(task)
wsp = fun.workspace{2,1}
fprintf('\n');
pause(2);

Запустите измененную функцию, чтобы увидеть выход functions команда и содержимое одного из workspace камеры:

showImageOutsidePath('greens.jpg')

Opening the figure greens.jpg
Displaying information from the function handle:
fun = 
     function: '@()restore_env(fig1,imgpath)'
         type: 'anonymous'
         file: 'c:\work\g6.m'
    workspace: {2x1 cell}
wsp = 
     imageFile: 'greens.jpg'
          fig1: 1
       imgpath: [1x3957 char]
    cleanupObj: [1x1 onCleanup]
           rgb: [300x500x3 uint8]
          task: @()restore_env(fig1,imgpath)

Closing the figure
Restoring the path

Использование onCleanup Verson version try/catch

Другой способ запуска стандартной программы очистки, когда функция неожиданно прекращает работать, - это использовать try, catch оператор. Однако существуют ограничения на использование этого метода. Если пользователь заканчивает программу, вводя Ctrl+C, MATLAB немедленно выходит из try блок, и стандартная программа очистки никогда не выполняется. Очистка стандартной программы также не запускается, когда вы обычно выходите из функции.

Следующая программа очищается, если происходит ошибка, но не в ответ на Ctrl+C:

function cleanupByCatch
try
    pause(10);
catch
    disp('   Collecting information about the error')
    disp('   Executing cleanup tasks')
end

В отличие от try/catch оператор, onCleanup функция реагирует не только на нормальный выход из программы и любую ошибку, которая может быть выдана, но и на Ctrl+C. Этот следующий пример заменяет try/catch с onCleanup:

function cleanupByFunc
obj = onCleanup(@()...
    disp('   Executing cleanup tasks'));
pause(10);

onCleanup в скриптах

onCleanup не работает в скриптах, как в функциях. В функциях объект очистки хранится в рабочей области функции. Когда функция выходит, эта рабочая область очищается, таким образом, выполняя связанную с ней стандартную программу очистки. В скриптах объект очистки хранится в базовом рабочем пространстве (то есть рабочей области, используемом в интерактивной работе, выполненной в командной строке). Поскольку выход из скрипта не имеет эффекта в базовом рабочем пространстве, объект очистки не очищается, и стандартная программа, связанная с этим объектом, не выполняется. Чтобы использовать этот тип механизма очистки в скрипте, вам придется явным образом очистить объект из командной строки или другого скрипта, когда первый скрипт завершится.