罗兰谈MATLAB的艺术

将想法转化为MATLAB

请注意

罗兰谈MATLAB的艺术已存档,不会更新。

解构析构函数

我很高兴介绍嘉宾博主Jennifer Black, MATLAB对象系统团队的经理。今天Jennifer将分享一些关于在MATLAB中销毁对象时会发生什么的想法,以及如何控制这个过程的各个方面。

内容

为什么定义析构函数

当一个类的实例被清除时,MATLAB会自动清除该对象拥有的属性值。例如,如果我有一个信号类的属性,该属性存储双精度值的矩阵信号被摧毁。然而,有时可能需要额外的操作来处理外部资源。

让我们考虑以下类:

类型FileReader1
classdef FileReader1 <句柄属性FileID end结束

在MATLAB中,文件标识符是返回的整数打开外部文件函数。它被文件I/O函数使用,例如从文件中读而且写入文件访问该文件。如果fopen无法打开文件,则返回-1。

如果我有空位的话FileReader命名读者在我的工作空间,清理读者将导致MATLAB清除存储在我的值文件标识财产。现在号码没了,但文件还在打开。清算文件标识没有首先关闭文件意味着即使不再使用该文件,该文件仍保持打开状态。如果这种情况发生足够多次,我可能会用完系统文件句柄。

让我们看看如何定义析构函数来关闭文件句柄。析构函数是类的一个方法,负责清理对象拥有的资源。在MATLAB中,句柄超类用于各种具有独立于其当前状态的唯一标识的对象。与数字、矩阵等不同,句柄对象表示具有开始和结束的唯一事物,并可能在此过程中改变内部状态。的任何子类处理可以定义一个名为删除,通常称为析构函数。在我的情况下FileReader类中,我可以通过实现自己的析构函数来纠正泄露文件句柄的问题:

类型FileReader2
classdef FileReader2 <处理属性FileID结束方法函数删除(readerObj) fclose(readerObj.FileID);结束结束

定义析构函数

MATLAB析构函数接受一个输入参数——被销毁的对象——并且不返回任何输出。输入对象总是标量,即使一组MATLAB对象一次全部超出作用域。

在MATLAB类中,您可以定义一个名为删除这不是析构函数。一个删除具有不同签名的方法不是析构函数,也不是静态方法删除方法。例如,将方法定义为接受多个输入参数或返回任何输出参数意味着该方法不被视为对象析构函数。

调用析构函数

对象析构函数可以显式调用删除方法,或者在MATLAB中隐式地使用,例如当变量被清除或超出范围时。让我们考虑一下这两个动作之间的区别。为此,我将添加一个构造函数和一个readData类的方法:

类型FileReader3
classdef FileReader3 <处理属性(SetAccess = protected) FileID = -1;文件名结束方法函数reader = FileReader3(fname)如果ischar(fname) reader。文件名= fname;读者。文件标识= fopen(fname,'r'); end end function colorData = readData(reader) if reader.FileID == -1 error('No file name has been specified for this FileReader. No data will be read.'); else colorData = fscanf(reader.FileID,'%f',[3,inf]); colorData = colorData'; frewind(reader.FileID); end end function delete(reader) if reader.FileID ~= -1 s = sprintf('Closing %s', reader.FileName); disp(s); fclose(reader.FileID); end end end end

首先,让我们考虑这样的情况,我有一个变量持有aFileReader

myReader = FileReader3(“colorData.txt”);

显式地调用删除myReader调用析构函数,然后销毁FileReader.的myReader变量仍然在我的工作空间中,但它的句柄不再有效:

删除(myReader);
关闭colorData.txt
isvalid (myReader)
Ans = 0

如果清除,将发生对析构函数的隐式调用myReader在我的工作空间:

myReader = FileReader3(“colorData.txt”);清晰的myReader
关闭colorData.txt

如果我的变量超出了作用域(例如,因为函数已经到达了末尾),析构函数也将被隐式调用。为了说明这一点,让我们添加一个帮助函数,我在其中创建了一个FileReader

类型readDataFromFile
函数colorData = readDataFromFile(文件名)myReader = FileReader3(文件名);colorData = readData(myReader);结束

当我调用新的helper函数时,myReader在函数中创建,并在函数结束时超出作用域。方法的隐式调用将导致MATLAB清除变量删除方法:

colordata = readDataFromFile(“colorData.txt”);
关闭colorData.txt

现在,让我们将刚才讨论的单个句柄与多个句柄相同的情况进行对比FileReader.例如,当我创建一个句柄对象,然后将该句柄分配给另一个工作区变量时,就会发生这种情况:

reader1 = FileReader3(“colorData.txt”);Reader2 = reader1;

这两个把手是一样的FileReader现在在我的工作空间中,我将显式调用删除,然后使用isvalid方法查看发生了什么FileReader对象:

删除(reader1);
关闭colorData.txt
isvalid (reader1)
Ans = 0
isvalid (reader2)
Ans = 0

不出所料,reader1句柄不再有效,但请注意reader2也不再有效。为什么会发生这种情况?因为当我显式调用删除,无论有多少句柄引用该对象,都将调用析构函数并销毁该对象。

现在让我们看看隐式调用析构函数时会发生什么。让我们再一次创建两个相同的句柄FileReader

reader1 = FileReader3(“colorData.txt”);Reader2 = reader1;

但这一次,我不显式地调用析构函数,而是只清除其中一个句柄。前面已经看到,这可能导致隐式调用删除方法:

清晰的reader1;isvalid (reader2)
Ans = 1

为什么reader2仍然有效,为什么没有调用析构函数?因为MATLAB只会隐式地调用析构函数最后的清除对对象的引用。作为reader2仍然存在于我的工作空间,底层FileReader并没有被摧毁。

析构函数通常定义为公共方法,但也可以声明为私有方法或受保护方法。将其设为private将防止类外部的代码显式调用析构函数。类似地,受保护析构函数只能从同一类的方法或子类方法显式调用。MATLAB将始终能够隐式调用析构函数,即使是声明为private或protected的析构函数。在希望防止意外删除对象的情况下,例如当您有一个单例对象时,可以选择限制对析构函数的访问。

包含在其他结构中的句柄

当句柄存储为结构的字段或单元格数组的单元格或另一个对象的属性时会发生什么?当顶层容器变量被销毁时,句柄对象也将被销毁删除方法,当且仅当不存在对对象的其他引用时隐式调用。让我们看一个使用结构体的例子:

s.myReader = FileReader3(“colorData.txt”);清晰的年代
关闭colorData.txt

注意FileReader存储在myReader领域的年代已经被摧毁了。然而,正如我们前面看到的,相同的另一个句柄FileReader将防止对象的破坏:

reader4 = FileReader3(“colorData.txt”);s.myReader = reader4;清晰的年代isvalid (reader4)
Ans = 1

即使在清理之后年代我们可以看到reader4仍然有效。第二个句柄防止隐式销毁对象。

层次结构中的类

到目前为止,我们已经看到了独立类的例子,但是作为层次结构一部分的类呢?在MATLAB中,每个类都有能力控制自己的破坏行为。在类的层次结构中,每个类都可以定义自己的析构函数。因此,析构函数不能定义为密封方法。

当一个对象被销毁时,MATLAB将首先调用该对象的类的析构函数(如果它已被定义)。接下来,调用每个超类的析构函数,从最直接的超类开始。

析构函数可以引用类本身的属性,包括从超类继承的属性,但它通常不应该引用子类的属性。为什么?因为当父类析构函数执行时,其子类的析构函数已经执行,并且可能使其属性中的值无效。

如何使用析构函数?

既然我们已经讨论了在MATLAB中使用析构函数方法的基础知识,我想听听你的经验。你已经在使用析构函数了吗?如果你有任何有趣的申请或问题,我很乐意听到在这里




MATLAB®R2013a发布


  • 打印
  • 发送电子邮件

评论

如欲留言,请点击在这里登录您的MathWorks帐户或创建一个新帐户。

Baidu
map