【问题标题】:c++ segmentation fault when deleting dynamic tables删除动态表时出现c ++分段错误
【发布时间】:2013-04-11 16:14:07
【问题描述】:

我必须创建一个动态矩阵,这是我拥有的构造函数和析构函数:

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,它是这里的类型而不是程序中的类型

【问题讨论】:

  • 向我们展示Memory()函数的实现。
  • 显示你的 Memory() 代码
  • board=Board(5,5);行不通,这是 c++,而不是 Board board = new Board(5,5); a_c 和 a_l 是什么类型?
  • 他们都是int。 @tacp,Memory=rMemory,复制代码时打错了
  • @Infested,“board=Board(5,5); 不起作用” - 为什么?

标签: c++ class pointers constructor


【解决方案1】:
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);
}

【讨论】:

  • 但是我需要复制实际对象,这就是为什么我有方法复制
  • @p.bosch 是的,您需要 copy() 来复制数据。那没有改变。我评论了列和行分配,因为您在调用 copy() 之前已经在 Board::Board(const Board&amp;t) 中完成了它们
  • 我已经这样做了,但现在我在 a_mp = new int[t.a_l][t.a_c]; 't' 和 '.'不能出现在常量表达式中。它们是什么意思?
  • @p.bosch 你是如何在课堂上声明 a_mp 的?
  • 这些是类中的属性: private: int a_l;诠释 a_c; char ** a_mp;
【解决方案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-&gt;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,它分配了一个内存块,仅在Memory内部称为a_mp,然后泄漏(当该局部变量超出范围时)
  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 在评论中指出的那样,rule of three 建议您也应该这样写:

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

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

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

    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;
    }

【讨论】:

【解决方案3】:
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;

【讨论】:

  • 我还建议您删除复制和复制构造函数,并首先使其与普通构造函数一起使用。即写Board foo(5,5); foo.cols(); foo.stuff(); foo.anything_else(); 并确保它也干净地退出而不会崩溃。然后添加复制功能。因为你在这里显然有很多不同的错误。我刚刚处理了第一个。
  • 是的!有用。但我仍然收到第二个错误: cout 之后立即调用它
  • @p.bosch 试试这个没有 const 的函数。
  • @Infested 如果你的意思是 board.Cols() 我试过了,但没有区别,仍然没有保存值。
  • 这与您的 copy() 函数相同。删除 `int a_l, a_c;` 并确保它们是成员并且 Cols() 可以工作。否则,请停止使用复制构造函数,如果您像我上面那样声明变量,它将起作用。
【解决方案4】:

for(int i=0;i&lt;a_l-1;i++) in freeMemoryi=0 运行到i=3,这是最后一个 i,即 5-1。 由于您的分配循环运行是for(int i =0;i&lt;a_l; i++),因此您缺少一行,因此从i=0 运行到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];
        }
    }
}

我做了什么:

看起来像这样:

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”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-27
    • 2012-01-14
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    相关资源
    最近更新 更多