每个人我都要创建一个动态矩阵,这里是我的构造函数和析构函数:
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);
我不知道为什么它崩溃了,我不知道为什么它没有保留我声明的板变量的值! 谁知道为什么?
编辑:rMemory =记忆,这是一个来自这里的类型而不是来自程序
答案 0 :(得分: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);
}
答案 1 :(得分: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);
}
确实
a_mp
指针)Memory
,它分配新的内存块,仅在a_mp
内部称为Memory
,然后泄露(当该局部变量熄灭时)范围)copy
,它将原始对象值复制到一个名为a_mp
的未初始化的本地指针中(这是未定义的行为,因为这些写操作可以去任何地方)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]='-';
}
}
};
请注意,如果仅使用复制构造函数,则此方法可以正常工作,但默认生成的赋值运算符仍然是错误的。正如丹尼尔·韦伯在评论中指出的那样,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;
}
答案 2 :(得分:1)
for(int i=0;i<a_l-1;i++)
中的 freeMemory
从i=0
到i=3
,这是&lt; 5-1
。
由于您的分配循环运行for(int i =0;i<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];
}
}
}
我做了什么:
Memory()
看起来像这样:
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;
打印:“Cols是:5”。
答案 3 :(得分: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应该是一个成员变量,因此在内存完成后你仍然可以引用你的数据。因此,你的析构函数知道要释放什么内存。
即。删除此行:char ** a_mp;