前几天我写了一个模板类,如下所示:
template <class T>
class Matrix {
private:
T ** matrix;
int n;
int m;
.
.
.
}
构造函数:
template <class T>
Matrix<T>::Matrix(int _n, int _m)
{
n = _n;
m = _m;
matrix = new T * [n];
for (int i = 0; i < n; i ++)
{
matrix[i] = new T[m];
}
}
现在我想创建一个这样的析构函数:
template <class T>
aghMatrix<T>::~aghMatrix()
{
for (int i = 0; i < n; i ++)
{
delete [] matrix[i];
}
}
起初我以为它会解决所有问题,但我错了。
在函数main
中:
Matrix<int> a; //destructor works find
Matrix<int*>a; //error destructor
如何解决这个问题?
答案 0 :(得分:0)
我将假设这是某种编码练习。对于真实世界的应用程序,您不应该编写自己的矩阵实现,而是依赖于标准库中的容器或其中一个矩阵库。
发布的示例有几个问题,甚至无法编译。所以,让我首先提供一个最小的解决方案:
template <class T>
class Matrix {
public:
Matrix(int _n, int _m)
: n(_n), m(_m), matrix(new T*[n]) // always initialize your members
{
for (int i=0; i<n; i++)
{
matrix[i] = new T[m];
}
}
~Matrix()
{
for (int i=0; i<n; i++)
{
delete[] matrix[i];
}
delete[] matrix; // this deletes the first level
}
private:
int n;
int m;
T ** matrix;
};
从中可以了解到:
确保初始化构造函数中的每个类成员 出于安全和性能原因的初始化列表
不要忘记删除第一级指针所指向的内存(析构函数中的最后一行)
如果您不必使用明确的new
和delete
复制和移动语义怎么样?它们已被定义,但不会做它们应该做的事情。
为了使用RAII并避免明确delete
,您可以使用std::unique_ptr代替{{3}}。等效代码现在看起来像这样:
#include <memory>
template <class T>
class Matrix2 {
public:
Matrix2(int _n, int _m)
: n(_n), m(_m), matrix(new T[n * m])
{}
private:
int n;
int m;
std::unique_ptr<T> matrix;
};
更简单,更不容易出错。唯一指针现在正在处理资源管理。请注意,我分配n * m
类型的T
对象,这意味着您的矩阵访问运算符将如下所示:
T operator()(int i, int j)
{
return matrix.get()[i * n + j];
}
unique_ptr可以移动但不能复制,这意味着您现在可以安全地移动Matrix2
但不能复制。必须明确定义复制语义:
Matrix2(const Matrix2& other)
: n(other.n), m(other.m), matrix(new T[n * m])
{
std::copy(other.matrix.get(), other.matrix.get() + n * m, matrix.get());
}
Matrix2& operator=(const Matrix2& other)
{
if (this != &other)
{
n = other.n;
m = other.m;
matrix.reset(new T[n * m]);
std::copy(other.matrix.get(), other.matrix.get() + n * m, matrix.get());
}
return *this;
}
请注意,此代码仅用于演示目的,但仍然缺少重要方面,不应在实际应用程序中使用。