C++ 将二维数组推入向量并删除该数组,但会导致分段错误

C++ 将二维数组推入向量并删除该数组,但会导致分段错误,c++,class,pointers,matrix,vector,C++,Class,Pointers,Matrix,Vector,我有一个叫做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

我有一个叫做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;
    };
模板
类矩阵{
公众:
矩阵(整数行,整数列){
行=行;列=列;
数据=新类型*[行];
对于(int i=0;i
我有一个向量来保存矩阵。每次我有一个矩阵,我会推回这个向量中的矩阵,以便将来计算。为了避免内存泄漏,我想在将矩阵推回向量后删除它。但是如果我不删除它,程序就会工作;如果我删除它(如下面的代码所示),当我想对这个向量进行一些计算时,程序将显示分段错误。我使用的代码如下所示

    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;
    }
向量v; 对于(int i=0;i<10;++i){ 矩阵a(3,3); ……我填充了a.data的元素 v、 推回(a); 对于(int j=0;j 希望我已经把我的问题解释清楚了。如果有什么让你困惑,请评论我


谢谢你的帮助

您的
矩阵
类没有正确的
复制构造函数
,因此当您将新矩阵推送到
向量
时,所有字段都会复制到
向量
中新创建的
矩阵


矩阵::数据
也作为指针复制。这意味着
向量
中的新
矩阵
指向与您在
for
循环中创建的
矩阵
相同的
矩阵。因此,当您删除
a
时,实际上会使
向量中的
矩阵
无效。

我发现您的代码中存在多个问题:

    它是C++,你是手动分配矩阵的内存,为什么?
  • 即使您有权访问析构函数,您也不会实现它,但可以在主代码中手动删除矩阵的数据
  • 您的方法没有清楚地管理内存,当您按值向后推时,
    矩阵被复制到向量中,此时谁拥有数据的指针?堆栈上的副本还是向量内部的副本
通过为类实现正确的复制构造函数、复制赋值运算符和析构函数,您应该小心地管理内存。

<>但是这是无关的,因为你可以使用C++的特性,忘记这些问题,有些解决方案:

在向量中存储指针 现在一切都是自动管理的,您不需要释放内存,也不需要矩阵的析构函数

std::vector<Matrix<3,3,float>> v;
Matrix<3,3,float> m;
v.emplace_back(m);
m.data[0][0] = 1;
std::vector v;
矩阵m;
v、 后侵位(m);
m、 数据[0][0]=1;
如果您希望在同一个向量中有不同大小的矩阵,或者希望保持较低的堆栈使用率(因为未动态分配
std::array
),则使用
std::vector
,而不是
std::array
,这样您就可以删除模板参数。

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]; 
    }
}
矩阵(int行,int列)
{
行=行;列=列;
数据=新类型*[行];
对于(int i=0;i
析构函数删除所有内存,因此不会发生泄漏

~Matrix() 
{  // you need a destructor
    for (int i = 0; i < rows; ++i)
        delete[] data[i];
    delete data;
}
~矩阵()
{//您需要一个析构函数
对于(int i=0;i
但是,没有复制或移动构造函数,也没有赋值或移动运算符,因此默认值只是复制指针,从而导致两个对象指向同一内存

不仅当一个副本被更改时,两个副本都会被修改,而且当一个副本被删除时,另一个副本的指针也会变得无效

这通常被认为是不好的

解决方案一是创建复制和移动构造函数以及赋值和移动操作符,但这需要做一些工作才能正确

谢天谢地,它是从盒子里拿出来的

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;
};
模板
类矩阵{
公众:
矩阵(整行,整列):行(行),列(列),数据(行,标准::向量(列))
{
//什么都不做。所有的重担都在初始化器中
}
//不再需要析构函数。
公众:
int行;
int cols;
std::矢量数据;
};
我建议的下一点是性能增强。因为向量的向量实际上是一个包含其他向量的向量,所以它并不都在一个内存块中。必须在RAM中跳转才能找到下一个数据位的成本可能会很高。抬头看看原因

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;
};
模板
类矩阵{
公众:
矩阵(整行,整列):行(行),列(列),数据(行*列)
{
//什么都不做。所有的重担都在初始化器中
}
//不再需要析构函数。
//添加一个方便的方法,以便轻松访问向量
类型和运算符()(行大小、列大小)
{
返回数据[行*列+列];
} 
类型运算符()(大小列,大小列)常量
{
返回数据[行*列+列];
} 
private://注意更改对private的访问权限,最好将自己的数据保密
int行;
int cols;
std::矢量数据;
};
现在,您可以安全地进行以下操作:

std::vector<Matrix<float>> v;
Matrix<float> m(3,3);
v.emplace_back(m);
m(0,0) = 1;
std::vector v;
矩阵m(3,3);
v、 后侵位(m);
m(0,0)=1;

对于此类问题,使用执行程序可能有助于揭示有关分段错误和其他内存泄漏的详细信息。当
推回时,您创建了一个具有相同指针的副本(指针按值复制)。然后它指向同一个内存,然后将其删除。你想加入cre吗
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;