C++ 返回异常,我应该释放资源吗?

C++ Returning exception, Should I free resources?

本文关键字:释放资源 我应该 返回 异常 C++      更新时间:2023-10-16

我为我的构造函数编写了以下实现:

template<class T>
Matrix<T>::Matrix(const Dimensions &matrix_dimensions, const T &initial_value) : dimensions(matrix_dimensions),
           data(new T[size()]) {
if (matrix_dimensions.getRow() <= 0 || matrix_dimensions.getCol() <= 0) {
return IllegalInitialization();
}
int matrix_size = size();
for (int i = 0; i < matrix_size; ++i) {
data[i] = initial_value;
}
}

因此,如果发生错误,我将返回IllegalInitialization()缓存,但是我使用new分配的资源呢? 如何在返回之前释放它们,我应该叫删除吗?

只是一个旁注:我是这个领域的新手,所以有人可以检查上面的代码是否写得很好(性能明智,理论上按预期工作(

假设你的意思是throw而不是return(你不能从构造函数返回值!(,以便取消对象的创建,是的,你必须先delete[] data

通常的方法是递归应用"资源获取正在初始化"模式。也就是说,data的类型不应该是原始指针,而应该是一些智能类型(如std::unique_ptr<T[]>(,当它超出范围时会自动执行此删除。

(反过来,std::unique_ptr内部是异常安全的。

如果你确实只是早return,那么你就有更大的问题——对象处于无用状态,而拥有范围不知道它,并且你使用return参数构建失败(因为,再次,你不能从构造函数返回值!

首先,问题中的代码永远不会编译,因为构造函数不能返回值。 因此,构造函数中return IllegalInitialization();的语句是可诊断的错误。

为了这个答案的目的,我假设你实际上使用了throw IllegalInitialization();

其次,所示代码可能存在泄漏。data是用new表达式初始化的,因此data的类型必须是指向与T兼容的类型的指针(例如,指向T基的指针(,或者它必须是具有接受此类指针的构造函数的类类型(例如std::unique_ptr<T>(。 如果data属于任何其他类型(例如intdouble( 那么data的初始化是一个可诊断的错误,因为(例如(指针不能隐式转换为int

如果data是原始指针,则在构造函数中引发异常将导致泄漏。 不会释放使用new表达式分配的对象或数据。

如果data是一个类,其构造函数接受指针,则有两种可能性(代码将编译,并且没有未定义的行为(。

  1. 类构造函数保存指针,析构函数释放它(使用delete [],因为它对应于new表达式(,然后动态分配的数据将被安全地释放。 此类的一个示例是类型std::unique_ptr<T[]>。 这是代码可以避免泄漏的唯一情况。
  2. 否则,将出现内存泄漏。 即使Matrix<T>的析构函数清理了data,在构造函数主体中抛出异常的行为也会阻止调用Matrix<T>的析构函数(析构函数只能为已完全构造的对象调用 - 这意味着构造函数已完成而没有抛出异常(。

(还有其他情况,例如data是一个具有析构函数的类的实例,该类使用错误的delete表达式形式,但这些情况要么给出未定义的行为,要么以其他方式泄漏,所以我将忽略它们(。

第三(这更主观(,您使用Dimensions类型(可能包含一对整数值(来表示矩阵维度。 本质上,你有一个要求,在Matrix,维度是正的。 由于如果维度为非正值,则会抛出异常,因此我建议由Dimensions类进行检查(例如,如果给定非正值,构造函数会抛出,则抛出一个 setter(如SetRow()要么忽略无效值,要么在给定无效值时抛出异常(。 如果这由Dimensions类型一致地完成,那么Matrix<T>可以安全地假设维度是有效的 - 因为不可能传递具有无效值的Dimensions实例。 这意味着,Matrix<T>不需要检查。