2013-04-18 19 views
0

大家要我做一個動態矩陣和這裏的構造函數和析構函數,我有:C++分段錯誤刪除動態表時

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]='-'; 
    } 
} 

董事會類和A_L和a_c是行和列數矩陣。在我的主,我宣佈一個局變量,然後我做到這一點:

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

顯示我們執行'內存()'函數。 – soon

+0

顯示您的代碼Memory() – taocp

+0

board = Board(5,5);不會工作,這是C++,而不是董事會董事會=新董事會(5,5);什麼類型是a_c和a_l? – Infested

回答

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_mp僅內部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]='-'; 
     } 
    } 
}; 

請注意,這工作得很好,如果你只使用拷貝構造函數,但是默認生成的賦值運算符將仍然是錯誤的。正如丹尼爾·韋伯在評論中指出,該rule of three建議你應該寫這個還有:

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

非常感謝,你解決了我的第二個問題! –

+0

這個答案缺乏三條規則(http://stackoverflow.com/questions/4172722/what-is-the-rule-of-ree)。通過使用構造函數可以繞過缺少賦值運算符的問題。 – Pixelchemist

+0

好點 - 最小的變化太小了。 – Useless

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); 
} 
+0

但我需要複製實際的對象,這就是爲什麼我有方法副本 –

+0

@ p.bosch是的,你需要copy()來複制數據。這並沒有改變。我評論了列和行分配,因爲在調用copy() – stardust

+0

之前,你已經在'Board :: Board(const Board&t)'中完成了它們。我已經完成了這一步,但現在我得到了2行錯誤a_mp = new int [t.a_l] [t.a_c];這是't'和'。'不能出現在常量表達式中。他們的意思是什麼? –

1

for(int i=0;i<a_l-1;i++)i=0freeMemory奔跑i=3,這是我最後一次是< 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()
  • 刪除a_mp的聲明添加一個賦值運算符 - >What is The Rule of Three?
  • 檢查在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; 

打印:「Cols are:5」。

+0

試過了,相同的錯誤在同一行 –

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;

+0

我也可以建議您刪除副本和複製構造函數,並讓它首先使用正常的構造函數。即寫'Board foo(5,5); foo.cols(); foo.stuff(); foo.anything_else();'並且確保它也乾淨地退出而不會崩潰。然後添加複製功能。你顯然有很多不同的錯誤。我剛剛處理了第一個。 – Salgar

+0

是的!有用。但我仍然得到第二個錯誤:cout << board.Cols()<< endl;這並不顯示實際的列,它顯示0.我打電話給董事會之後(董事會)(5,5) –

+0

@ p.bosch試試這個函數沒有最後的const。 – Infested