将二维数组推入矢量并删除数组,但会导致分割错误
push a 2D array into a vector and delete the array, but cause segmentation fault
我有一个名为Matrix的类。类中有一个2D数组来保存数据。
template <class Type>
class Matrix{
public:
Matrix(int row, int col){
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++){
data[i] = new Type[cols];
}
}
public:
int rows;
int cols;
Type **data;
};
我有一个向量来保存矩阵。每次我有一个矩阵,我都会把这个向量中的矩阵推回去以便将来的计算。为了避免内存泄漏,我想在将矩阵推回向量后删除它。但如果我不删除它,程序就能运行;如果我删除它(如下面的代码所示),当我想对这个向量做一些计算时,程序将显示分割错误。我使用的代码如下所示
vector<Matrix<int>> v;
for(int i = 0; i < 10; ++i){
Matrix<int> a(3,3);
...... // I fill the elements of a.data
v.push_back(a);
for(int j = 0; j < a.rows; ++j)
delete[] a.data[j];
delete[] a.data;
}
希望我已经清楚地解释了我的问题。如果有什么让你困惑,请评论我。
谢谢你的帮助!
我看到你的代码中有多个问题:
- 这是c++,你是手动分配内存的矩阵,为什么?
- 即使你可以访问析构函数,你也不实现它,而是在主代码中手动删除矩阵的数据
- 你的方法不能清楚地管理内存,当你按值
push_back
时,Matrix
被复制到向量内部,谁拥有此时数据的指针?堆栈上的复制还是向量内的复制?
您应该通过为类实现正确的复制构造函数、复制赋值操作符和析构函数来小心地管理内存。
但这是无关的,因为你可以只使用c++的特性,忘记这些问题,一些解决方案:
在vector
中存储指针class Matrix{
public:
Matrix(int row, int col){
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++){
data[i] = new Type[cols];
}
}
~Matrix() { // you need a destructor
for (int i = 0; i < rows; ++i)
delete[] data[i];
delete data;
}
public:
int rows;
int cols;
Type **data;
};
std::vector<std::unique_ptr<Matrix>> v;
Matrix* matrix = new Matrix(3,3);
v.push_back(std::unique_ptr<Matrix>(matrix));
现在矩阵是持久的,但是当v
超出范围时(由于unique_ptr
和析构函数),它们将被自动释放
为矩阵元素使用std::vector
/std::array
你用它们来存储多个矩阵,为什么不把它们也用于矩阵本身呢?
template<size_t ROWS, size_t COLS, class TYPE>
class Matrix
{
std::array<std::array<COLS, TYPE>, ROWS> data;
...
}
现在一切都是自动管理的,你不需要释放内存,也不需要Matrix
的析构函数。
std::vector<Matrix<3,3,float>> v;
Matrix<3,3,float> m;
v.emplace_back(m);
m.data[0][0] = 1;
如果你想在同一个向量中有不同大小的矩阵,或者如果你想保持堆栈使用率低(因为std::array
不是动态分配的),那么使用std::vector
而不是std::array
,这样你就可以删除模板参数。
您的Matrix
类没有适当的copy constructor
,所以当您将新矩阵推到vector
时,所有字段都复制到vector
内新创建的Matrix
。
AND Matrix::data
也作为指针复制。这意味着vector
中的新Matrix
指向与您在for
循环中创建的 Matrix
a
相同的。因此,当您删除a
时,您实际上使vector
中的Matrix
无效。
OP的问题违反了经典的"三原则"
类使用原始指针指向构造函数
分配的内存Matrix(int row, int col)
{
rows = row; cols = col;
data = new Type*[rows];
for(int i = 0; i < rows; i++)
{
data[i] = new Type[cols];
}
}
析构函数删除所有内存,因此不会有泄漏。
~Matrix()
{ // you need a destructor
for (int i = 0; i < rows; ++i)
delete[] data[i];
delete data;
}
但是,没有复制或移动构造函数,也没有赋值或移动操作符,因此默认值将简单地复制指针,导致两个对象指向相同的内存。
当一个副本被修改时,不仅两个副本都被修改,而且当一个副本被删除时,另一个副本的指针也无效。
这通常被认为是不好的。
解决方案一是创建复制和移动构造函数,赋值和移动操作符,但这需要一些工作才能正确。
值得庆幸的是,std::vector让它直接开箱即用。
template<class Type>
class Matrix{
public:
Matrix(int row, int col):rows(row), cols(col), data(rows, std::vector(cols))
{
// does nothing. All of the heavy lifting was in the initializer
}
// no longer need a destructor.
public:
int rows;
int cols;
std::vector<std::vector<type>> data;
};
下一段我建议作为性能增强。因为向量的向量实际上是一个包含其他向量的向量,它并不都在一个内存块中。不得不在RAM中跳转来查找下一个数据位的成本很高。查看Cache Miss和Spatial locality来了解原因。
template<class Type>
class Matrix{
public:
Matrix(int row, int col):rows(row), cols(col), data(rows*cols)
{
// does nothing. All of the heavy lifting was in the initializer
}
// no longer need a destructor.
//add a convenience method for easy access to the vector
type & operator()(size_t row, size_t col)
{
return data[row*cols+col];
}
type operator()(size_t row, size_t col) const
{
return data[row*cols+col];
}
private: // note change of access to private Best to keep ones data to one's self
int rows;
int cols;
std::vector<type> data;
};
现在你的东西是安全的,如:
std::vector<Matrix<float>> v;
Matrix<float> m(3,3);
v.emplace_back(m);
m(0,0) = 1;
- C++映射分割错误(核心转储)
- 由cin中的字符串中未捕获空白引起的分割错误
- 删除映射和分割错误中的一个过去结束元素
- 在指向函数中读取变量时出现分割错误
- 在链表中的第 n 位插入显示分割错误
- 较高值 n 的分割错误(例如 n=999997)
- 尝试通过memcpy复制大尺寸浮点向量时的分割错误
- 分割错误:向量中的擦除功能
- 向量向量的分割错误
- 我在C++中编写了一个方法来打印树类的预序,但它显示了分割错误
- C ++分割错误,为什么使用"long long"我没有得到答案?
- 在尝试使用递归查找集合子集的总数时,我遇到了分割错误
- 分割错误 11:尝试使用 cin 输入 B[1] 时
- 集合布局上的 Qt 分割错误
- 高达20亿的筛子会产生分割错误
- G :内部编译器错误:分割故障(程序CC1PLUS) - 我在哪里开始
- 二进制搜索树操作程序错误:分割故障(核心倾倒)
- 在给出正确的输出后,给出错误分割错误(核心转储)
- 得到错误分割错误(核心转储)进程返回139 (0x8B)
- 内部编译错误:分割错误在gcc.发送可变模板到struct时