CPP:矩阵析构函数
CPP: Matrix Destructor
对于下面的mymatrix
class定义,为什么我不需要析构函数的注释部分?我们不需要删除指针指向的内容吗?还是因为我们删除了所有有意义的数据,我们不需要析构函数的这些(注释掉的)部分?
template<typename T>
class mymatrix
{
private:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
}
析构函数:
virtual ~mymatrix()
{
for(int r=0;r<numRows;r++)
{
for(int c=0;c<Rows[r].NumCols;c++)
{
delete Rows[r].Cols[c];
}
// delete Rows[r];
}
// delete Rows;
}
构造函数:
mymatrix(int R, int C)
{
if (R < 1)
throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for(int r=0;r<R;r++){
Rows[r].Cols=new T[C];
Rows[r].NumCols=C;
//initialize elements to their default value
for(int c=0;c<Rows[r].NumCols;c++){
Rows[r].Cols[c]=T{}; // default value for type T;
}
}
}
您需要使用数组删除语法,因为您要删除的是数组,而不是单个对象:
delete[] Rows[r].Cols
...
delete[] Rows
编辑:我最初只是包含了正确的 delete[]
运算符用法,并在我的原始示例中为简洁起见保持一切不变,但正如@idclev463035818 指出的那样,无论何时您定义自己的析构函数、复制构造函数或复制赋值运算符(特别是当它们涉及动态内存分配时),您几乎总是需要同时拥有这三个。你几乎从不想要任何一个没有其他的,因为如果你的对象中有原始指针,那么它们将被浅复制到正在实例化的新对象中。然后,这些对象中的每一个的析构函数将被调用并多次尝试删除内存的相同部分,这是一个重大错误。我已将这些添加到代码示例中,并在 main
函数的新测试中使用它们。
完整代码:
#include <iostream>
using namespace std;
template<typename T>
class mymatrix
{
public:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
public:
mymatrix(int R, int C)
{
init(R, C);
}
void init(int R, int C) {
if (R < 1)
throw "";//throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw "";//invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for (int r = 0; r < R; r++) {
Rows[r].Cols = new T[C];
Rows[r].NumCols = C;
//initialize elements to their default value
for (int c = 0; c < Rows[r].NumCols; c++) {
Rows[r].Cols[c] = T{}; // default value for type T;
}
}
}
mymatrix(const mymatrix& other) : mymatrix(other.NumRows, other.Rows[0].NumCols) {
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
}
mymatrix& operator=(const mymatrix& other) {
if (other.NumRows != NumRows || other.Rows[0].NumCols != Rows[0].NumCols) {
clear();
init(other.NumRows, other.Rows[0].NumCols);
}
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
return *this;
}
void clear() {
for (int r = 0; r < NumRows; r++)
{
delete[] Rows[r].Cols;
}
delete[] Rows;
Rows = NULL;
NumRows = 0;
}
virtual ~mymatrix()
{
clear();
}
};
int main() {
mymatrix<int> mat(5, 5);
mat.Rows[0].Cols[2] = 5;
mymatrix<int> matClone(mat);
cout << matClone.Rows[0].Cols[2] << endl;
matClone.Rows[0].Cols[1] = 8;
cout << mat.Rows[0].Cols[1] << endl;
mat = matClone;
cout << mat.Rows[0].Cols[1] << endl;
system("pause");
return 0;
}
每次看到 new/delete
在 C++
中的用法时,我都会告诉这个。
请不要在C++
中使用new/delete
!
这是一个最小的示例,说明如何创建一个矩阵,该矩阵无需任何手动内存分配即可自行分配和删除。
#include <vector>
class Matrix : public std::vector<std::vector<int>> {
public:
Matrix(size_t numRows, size_t numCols)
: std::vector<std::vector<int>>(numRows, std::vector<int>(numCols, 0)) {}
size_t numRows() const { return size(); }
size_t numCols() const { return front().size(); }
};
int main() {
auto m = Matrix(5, 4);
return m[4][3];
}
对于下面的mymatrix
class定义,为什么我不需要析构函数的注释部分?我们不需要删除指针指向的内容吗?还是因为我们删除了所有有意义的数据,我们不需要析构函数的这些(注释掉的)部分?
template<typename T>
class mymatrix
{
private:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
}
析构函数:
virtual ~mymatrix()
{
for(int r=0;r<numRows;r++)
{
for(int c=0;c<Rows[r].NumCols;c++)
{
delete Rows[r].Cols[c];
}
// delete Rows[r];
}
// delete Rows;
}
构造函数:
mymatrix(int R, int C)
{
if (R < 1)
throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for(int r=0;r<R;r++){
Rows[r].Cols=new T[C];
Rows[r].NumCols=C;
//initialize elements to their default value
for(int c=0;c<Rows[r].NumCols;c++){
Rows[r].Cols[c]=T{}; // default value for type T;
}
}
}
您需要使用数组删除语法,因为您要删除的是数组,而不是单个对象:
delete[] Rows[r].Cols
...
delete[] Rows
编辑:我最初只是包含了正确的 delete[]
运算符用法,并在我的原始示例中为简洁起见保持一切不变,但正如@idclev463035818 指出的那样,无论何时您定义自己的析构函数、复制构造函数或复制赋值运算符(特别是当它们涉及动态内存分配时),您几乎总是需要同时拥有这三个。你几乎从不想要任何一个没有其他的,因为如果你的对象中有原始指针,那么它们将被浅复制到正在实例化的新对象中。然后,这些对象中的每一个的析构函数将被调用并多次尝试删除内存的相同部分,这是一个重大错误。我已将这些添加到代码示例中,并在 main
函数的新测试中使用它们。
完整代码:
#include <iostream>
using namespace std;
template<typename T>
class mymatrix
{
public:
struct ROW
{
T* Cols; // dynamic array of column elements
int NumCols; // total # of columns (0..NumCols-1)
};
ROW* Rows; // dynamic array of ROWs
int NumRows; // total # of rows (0..NumRows-1)
public:
mymatrix(int R, int C)
{
init(R, C);
}
void init(int R, int C) {
if (R < 1)
throw "";//throw invalid_argument("mymatrix::constructor: # of rows");
if (C < 1)
throw "";//invalid_argument("mymatrix::constructor: # of cols");
Rows = new ROW[R]; // an array with R ROW structs:
NumRows = R;
//intialize each row to C columns
for (int r = 0; r < R; r++) {
Rows[r].Cols = new T[C];
Rows[r].NumCols = C;
//initialize elements to their default value
for (int c = 0; c < Rows[r].NumCols; c++) {
Rows[r].Cols[c] = T{}; // default value for type T;
}
}
}
mymatrix(const mymatrix& other) : mymatrix(other.NumRows, other.Rows[0].NumCols) {
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
}
mymatrix& operator=(const mymatrix& other) {
if (other.NumRows != NumRows || other.Rows[0].NumCols != Rows[0].NumCols) {
clear();
init(other.NumRows, other.Rows[0].NumCols);
}
for (int r = 0; r < NumRows; ++r) {
ROW& thisRow = Rows[r];
ROW& otherRow = other.Rows[r];
for (int c = 0; c < thisRow.NumCols; ++c) {
thisRow.Cols[c] = otherRow.Cols[c];
}
}
return *this;
}
void clear() {
for (int r = 0; r < NumRows; r++)
{
delete[] Rows[r].Cols;
}
delete[] Rows;
Rows = NULL;
NumRows = 0;
}
virtual ~mymatrix()
{
clear();
}
};
int main() {
mymatrix<int> mat(5, 5);
mat.Rows[0].Cols[2] = 5;
mymatrix<int> matClone(mat);
cout << matClone.Rows[0].Cols[2] << endl;
matClone.Rows[0].Cols[1] = 8;
cout << mat.Rows[0].Cols[1] << endl;
mat = matClone;
cout << mat.Rows[0].Cols[1] << endl;
system("pause");
return 0;
}
每次看到 new/delete
在 C++
中的用法时,我都会告诉这个。
请不要在C++
中使用new/delete
!
这是一个最小的示例,说明如何创建一个矩阵,该矩阵无需任何手动内存分配即可自行分配和删除。
#include <vector>
class Matrix : public std::vector<std::vector<int>> {
public:
Matrix(size_t numRows, size_t numCols)
: std::vector<std::vector<int>>(numRows, std::vector<int>(numCols, 0)) {}
size_t numRows() const { return size(); }
size_t numCols() const { return front().size(); }
};
int main() {
auto m = Matrix(5, 4);
return m[4][3];
}