0

每个人我都必须制作一个动态矩阵,这是我拥有的构造函数和析构函数:

Board::Board() {
    a_l=0;
    a_c=0;
    a_mp=NULL;
}
Board::Board(const Board&t) {
    a_l=t.a_l;
    a_c=t.a_c;
    a_mp=t.a_mp;
    Memory();
    copy(t);
}
Board::Board(int nl, int nc) {
    a_l=nl;
    a_c=nc;
    Memory();
}
Board::~Board() {
    freeMemory();
}

// PRIVATE METHODS

void Board::copy(const Board &t) {
    int a_l, a_c;
    int ** a_mp;
    a_l=t.a_l;
    a_c=t.a_c;
    for(int i=a_l;i<a_c;i++) {
        for(int j=a_c;j<a_l;j++) {
            a_mp[i][j]=t.a_mp[i][j];
        }
    }
}
void Board::freeMemory() {
    for(int i=0;i<a_l-1;i++) {
        delete [] a_mp[i];
    }
    delete [] a_mp;
}
void Board::Memory() {
    char ** a_mp;
    a_mp = new char*[a_l];
    for(int i =0;i<a_l; i++) {
        a_mp[i]=new char[a_c];
        for(int j=0;j<a_c;j++)
            a_mp[i][j]='-';
    }
}

Board 是类,a_l 和 a_c 是矩阵的行数和列数。在我的主要声明中,我声明了一个 Board 变量,然后我这样做:

board=Board(5,5);

它可以编译,但是当我想显示它时,例如:

cout << board.Cols() << endl;

这是方法:

int Board::Cols() const {
    return (a_c);
}

它显示为 0。好像它没有使用我说的参数创建板。当我这样做时程序也会崩溃,board=Board(5,5);所以我使用调试器,它说它在删除的这一行停止:

board=Board(5,5);

我不知道它为什么会崩溃,也不知道为什么它不保留我声明的 board 变量的值!有谁知道为什么?

编辑:rMemory=Memory,它是这里的一种类型,而不是来自程序的类型

4

4 回答 4

3
int ** a_mp;

需要公正a_mp。否则,您将声明一个新变量。而不是使用会员一。

然后它需要被分配到。现在不是。


void Board::copy(const Board &t) {
    int a_l, a_c;
    a_mp = new char[t.a_l][t.a_c];
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // a_l=t.a_l; These have already be done in the copy constructor. 
    // a_c=t.a_c;
    for(int i=a_l;i<a_c;i++) {
        for(int j=a_c;j<a_l;j++) {
            a_mp[i][j]=t.a_mp[i][j];
        }
    }

}

或者如果你愿意,你可以在复制构造函数中分配它

Board::Board(const Board&t) {
    a_l=t.a_l;
    a_c=t.a_c;
    // a_mp=t.a_mp;  // This is wrong!!
    a_mp = new char[t.a_l][t.a_c];
    copy(t);
}
于 2013-04-18T13:52:59.960 回答
2

首先,这个任务

board=Board(5,5);

过于复杂。你可以声明

Board board(5,5);

直接(额外的工作可能会被优化,但它是不习惯的)。


其次,无论你在哪里做类似的事情:

void Board::copy(const Board &t) {
    int a_l, a_c;
    int ** a_mp;

您正在隐藏对象的成员变量。也就是说,a_l现在指的是这个函数内部的局部整数变量,而不是对象成员。this->a_l如果要查看或更改对象,则必须参考。


现在,复制构造函数

Board::Board(const Board&t) {
    a_l=t.a_l;
    a_c=t.a_c;
    a_mp=t.a_mp;
    Memory();
    copy(t);
}

做:

  1. 拷贝(它a_mp与您正在复制的对象共享指针)
  2. Memory分配内存块的调用,仅称为a_mpinside Memory,然后泄漏(当该局部变量超出范围时)
  3. 调用copy,它将原始对象的值复制到一个未初始化的本地指针中,也称为a_mp(这是未定义的行为,因为这些写入可以去任何地方)
  4. 最终得到a_mp它首先选择的值,所以现在两个 Board实例具有相同的a_mp值,它将被释放两次。

下面是一些解决这些问题的示例代码: 我已经尽可能少地更改了代码的结构(为了便于阅读而重命名事物)。有很大的改进空间,但至少应该是正确的。

class Board {
    int rows;
    int cols;
    char **data;
public:
    Board(): rows(0), cols(0), data(0) {}
    Board(int nl, int nc) : rows(nl), cols(nc) 
    {
        allocate_data();
    }
    Board(const Board& other)
        : rows(other.rows), cols(other.cols)
    {
        allocate_data();
        copy_data(other);
    }
    ~Board() {
        free_data();
    }
private:
    void copy_data(const Board &other) {
        for(int r=0; r<rows; r++)
            for(int c=0; c<cols; c++)
                data[r][c]=t.data[r][c];
    }
    void free_data() {
        for(int r=0; r<rows; r++)
            delete [] data[r];
        delete [] data;
    }
    void allocate_data() {
        data = new char*[rows];
        for(int r=0; r<rows; r++) {
            data[r]=new char[cols];
            for(int c=0; c<cols; c++)
                data[r][c]='-';
        }
    }
};

请注意,如果您使用复制构造函数,这可以正常工作,但默认生成的赋值运算符仍然是错误的。正如 Daniel Weber 在评论中指出的那样,三法则建议你也应该这样写:

    Board& operator=(const Board& other) {
        free_data();
        rows = other.rows;
        cols = other.cols;
        allocate_data();
        copy_data(other);
    }

请注意,复制赋值运算符需要处理已经初始化的目标对象,并且可能没有正确的维度。other如果新的 ( ) 板更大,您可以改进它以仅重新分配。

如果您有 C++11 支持,您还可以添加复制构造函数和赋值运算符的移动等效项:

    Board(Board&& original)
        : rows(original.rows), cols(original.cols)
    {
        data = original.data;
        original.data = NULL;
    }
    Board& operator=(Board&& original) {
        free_data();
        rows = original.rows;
        cols = original.cols;
        data = original.data;
        original.data = NULL;
    }
于 2013-04-18T14:06:16.603 回答
1

for(int i=0;i<a_l-1;i++)infreeMemoryi=0to运行i=3,这是最后一个 i 即 < 5-1。您缺少一行,因为您的分配 Loop 运行是for(int i =0;i<a_l; i++),因此从i=0to运行i=4。你再分配一条线。

另一件事是:copy() 是做什么的?您将 t.a_l 和 t.a_c 的值复制到临时变量,一旦复制结束,这些临时变量就会被删除,并将值分配给未分配的内存(临时 **a_mp)。删除此函数中的声明和赋值,只保留 a_mp 数据副本。

void Board::copy(Board const &t) {
    for(int i=a_l;i<a_c;i++) {
        for(int j=a_c;j<a_l;j++) {
            a_mp[i][j]=t.a_mp[i][j];
        }
    }
}

我做了什么:

  • 删除 a_mp 中的声明Memory()
  • 添加赋值运算符 ->什么是三法则?
  • 检查 freeMemory() 函数中的 NULL 指针

看起来像这样:

class Board
{
public:
  int a_l, a_c;
  char ** a_mp;

  Board() : a_l(0), a_c(0), a_mp(NULL) 
  {
  }
  Board(const Board&t) : a_l(t.a_l), a_c(t.a_c), a_mp(NULL) 
  {
    Memory();
    copy(t);
  }
  Board(int nl, int nc) : a_l(nl), a_c(nc), a_mp(NULL) 
  {
    Memory();
  }

  Board& operator= (Board const &t)
  {
    freeMemory();
    a_l = t.a_l;
    a_c = t.a_c;
    Memory();
    copy(t);
    return *this;
  }

  Board::~Board() 
  {
    freeMemory();
  }

  // PRIVATE METHODS

  void copy(const Board &t) 
  {
    for(int i=a_l;i<a_c;i++) 
    {
      for(int j=a_c;j<a_l;j++) 
      {
        a_mp[i][j]=t.a_mp[i][j];
      }
    }
  }
  void freeMemory() 
  {
    if (a_mp == NULL)
    {
      for(int i=0;i<a_l;i++) 
      {
        delete [] a_mp[i];
      }
      delete [] a_mp;
    }
  }
  void Memory() {
    a_mp = new char*[a_l];
    for(int i =0;i<a_l; i++) 
    {
      a_mp[i]=new char[a_c];
      for(int j=0;j<a_c;j++) a_mp[i][j] = '-';
    }
  }

  int Cols() const 
  {
    return (a_c);
  }

};

作品。

Board testboard;
testboard = Board(5,5);
cout << "Cols are: " << testboard.Cols() << endl;

打印:“列数:5”。

于 2013-04-18T14:01:50.920 回答
1
void Board::Memory() {
    char ** a_mp;
    a_mp = new char*[a_l];
    for(int i =0;i<a_l; i++) {
        a_mp[i]=new char[a_c];
        for(int j=0;j<a_c;j++)
            a_mp[i][j]='-';
    }
}

您在堆栈上声明了一个名为 a_mp 的局部变量。该指针指向堆上所有已分配的内存。然后它在对 Memory() 的调用结束时超出范围。现在您无法访问您刚刚分配的任何内存。这真是难过;这真是伤心。a_mp 应该是一个成员变量,以便在 Memory 完成后您仍然可以引用您的数据。这样你的析构函数就知道要释放什么内存。

即删除这一行:char ** a_mp;

于 2013-04-18T14:02:29.133 回答