【问题标题】:Assigning memory in C++在 C++ 中分配内存
【发布时间】:2018-08-12 11:45:16
【问题描述】:

我正在尝试学习如何在 C++ 中分配内存。我按照这个答案分配二维数组:Copy 2D array using memcpy?

但是,当我尝试将其与使用 std::copy 复制内存相结合时,我遇到了损坏。

#include <iostream>

class Matrix
{

  private:

    int nrows;
    int mcols;
    double **entry;


  public:

  Matrix(int n, int m);

  ~Matrix();

  Matrix& operator=(const Matrix& mat_in);

};

Matrix::Matrix(int n, int m)
{
  nrows = n;
  mcols = m;

  std::cout << "Using regular constructor" << std::endl;

  entry    = new double*[nrows];
  entry[0] = new double[nrows * mcols];
  for(int i=1;i<nrows;i++)
    entry[i] = entry[i-1] + mcols;

  for(int i=0;i<nrows;i++)
    for(int j=0;j<mcols;j++)
      entry[i][j] = 0.0;
}

Matrix::~Matrix()
{
  delete[] entry[0];
  delete[] entry;
}



Matrix& Matrix::operator=(const Matrix& mat_in)
{
  std::cout << "using deep copy constructor" << std::endl;

  if(this == &mat_in)
    return *this;

  double **p = new double*[mat_in.nrows];
  p[0] = new double[mat_in.nrows * mat_in.mcols];

  std::copy(mat_in.entry, mat_in.entry + (mat_in.nrows * mat_in.mcols), p);

  delete[] this -> entry;

  entry = p;
  nrows = mat_in.nrows;
  mcols = mat_in.mcols;

  return *this;
}
int main()

{
  Matrix A(3,3);

  Matrix B(3,3);

  B = A;

  return 0;
}

我认为问题在于我不完全理解当我释放内存并且我释放它两次时发生了什么。

【问题讨论】:

  • 为什么你觉得需要一个指针数组(“二维数组”)?为什么单个doubles 数组(大小为宽×高)不够用?这肯定会很多简单,然后你可能不会有这个问题。
  • 考虑向book 学习。
  • 考虑使用std::arraystd::vector 而不是C 数组,以便赋值的工作方式与整数相同。它使事情变得容易得多。
  • 请不要在现代 C++ 中使用手动内存管理。使用容器和智能指针以及 RAII..
  • @JohnMeighan 同样的问题也适用于 C.

标签: c++


【解决方案1】:

您混合了两种基本类型的二维数组分配。

在一种风格中,分配一个行指针数组(大小为 nRows),然后为每一行分配一个元素数组(大小为 nCols)。寻址一个元素是rows[r][c]

在另一种风格中,为整个事物分配一个元素数组(大小为 nRows*nCols)。寻址元素是elements[(r * nCols) + c]

【讨论】:

    【解决方案2】:

    您的复制赋值运算符有问题(尽管您的评论它不是复制构造函数)。特别是这个

    std::copy(mat_in.entry, mat_in.entry + (mat_in.nrows * mat_in.mcols), p);
    delete[] this -> entry;
    

    应该是这样的

    for(int i=1;i<mat_in.nrows;i++)
        p[i] = p[i-1] + mat_in.mcols;
    std::copy(mat_in.entry[0], mat_in.entry[0] + (mat_in.nrows * mat_in.mcols), p[0]);
    delete[] this -> entry[0];
    delete[] this -> entry;
    

    这里有很多重复的代码,你应该清理一下。您还应该查看copy and swap idiom,这是实现复制赋值运算符的常用方法。

    【讨论】:

    • 好的,谢谢,你能解释一下 entry[0] 和 entry 之间的区别吗?我以为它们都指向同一个地方?
    • 从你的构造函数中你有entry = new double*[nrows]; entry[0] = new double[nrows * mcols];。显然它们指向的不是同一个地方。
    • entry[0]*entry 或特别是 *(entry + 0) 相同。
    • 嗯,我的代码更接近但仍然不正确。我会编辑修复它。
    • @JohnMeighan 我认为我的代码现在是正确的,但你可能会说我没有测试任何东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 2019-01-17
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多