2012-07-31 73 views
0

我正在爲一個簡單的「節點」類寫一些C++代碼。這基本上是一個用來管理線性鏈表的類。我通常使用結構執行此操作,但我試圖更好地處理OOP和類。 (注意:String類是我的典型「字符串」類的版本(修剪下來),它實現了一個拷貝構造函數,賦值重載,析構函數等等。在測試中,偉大的工作,似乎完全獨立的):似乎從複製構造函數中獲取段錯誤?

class Node { 
public: 

    //Constructor 
    //----------- 

    Node() : next_(0) {} //inline (String constructor called) 

    //Destructor 
    //---------- 

    ~Node(); 

    //Copy Constructor 
    //---------------- 

    Node(const Node &);  

    //Operator Overload: = 
    //--------------------- 
    //In conjunction with copy constructor. Protects Class. 

    Node & operator=(const Node &); 

private: 

    String relatedEntry_; 
    Node * next_; 
}; 

創建一個實例正常工作(即Node node;),但是當我創建調用拷貝構造函數實例我在節目的最後結了段錯誤,因爲它正在清理。使用鏈接列表和類的結構之間的區別與我玩一些技巧,我想我在這裏丟失了一些關鍵。下面是默認的構造函數的實現,拷貝構造函數和重載賦值運算符:

//Constructor inlined 

//Destructor 
Node::~Node() 
{ 
    Node * curr = next_; 
    while (curr) //cycle through LL and delete nodes 
    { 
     Node * temp = curr; //hold onto current 
     curr = curr->next_; //increment one 
     delete temp; //delete former current 
    } 
} 


//Copy Constructor 
Node::Node(const Node & cp) 
{ 
    std::cout << "in CopyCon" << std::endl; 
    relatedEntry_ = cp.relatedEntry_; //calls String class copy constructor/assignment overload 
    Node * curr = cp.next_; //for clarity, for traversal 
    while (curr) //copies related entry structure 
    { 
     Node * oldNext = next_; 
     next_ = new Node; 
     next_->next_ = oldNext; //'next' field (assign prior) 
     next_->relatedEntry_ = curr->relatedEntry_; //String class copy 
     curr = curr->next_; //increment 
    } 
} 


//OO: = 
Node & Node::operator=(const Node & cp) 
{ 
    std::cout << "in OO: =" << std::endl; 
    if (this == &cp) 
     return *this; //self assignment 
    delete next_; //delete LL 
    relatedEntry_ = cp.relatedEntry_; //String Class Assignment Overload 
    Node * curr = cp.next_; //for clarity, for traversal 
    while (curr) 
    { 
     Node * oldNext = next_; //hold onto old 
     next_ = new Node; 
     next_->next_ = oldNext; //set next to old 
     next_->relatedEntry_ = curr->relatedEntry_; //set this string to cp string 
     curr = curr->next_; //increment 
    } 
    return *this; 
} 

注意使用重載定義功能似乎工作正常(無段錯誤),儘管它幾乎相同的代碼...我假設它與兩個對象在之前已經初始化這一事實有關,那麼分配發生了嗎?

//This seems to work ok 
Node node1; 
Node node2; 
node2 = node1; 

我一直在這個bug幾個小時,我得休息一下。我真的很感激任何見解。謝謝。

+0

在發生崩潰,分段錯誤或任何其他問題時,您應該做的第一件事是在調試器中運行您的程序。它不僅可以幫助您找到崩潰的位置,還可以讓您檢查變量以幫助您找出原因。 – 2012-07-31 07:06:39

+1

下一步應該在'Node * oldNext = next_; //保持舊''? – irrelephant 2012-07-31 07:09:06

+0

我不同意reark「_it幾乎相同的code_」。您的operator =的代碼與隱式代碼不是同一個代碼:您對整個列表進行深層次的複製,而默認賦值操作符只是對該對象進行淺度複製(字符串和指針的副本_next。 – Bentoy13 2012-07-31 07:16:30

回答

1

在拷貝構造函數循環,你有這樣一行:

Node * oldNext = next_; 

然而,在循環的第一輪next_值可以通過,嗯,什麼事,最有可能不NULL。這意味着最後一個節點將有一個非空指針。

在循環之前將其初始化爲NULL並且它應該起作用。

+0

在Node類的默認構造函數中,我將next_初始化爲0.這應該處理這個問題,不是嗎? – MCP 2012-07-31 14:25:50

+1

@MCP不,因爲未調用默認構造,所以只有複製構造函數。 – 2012-07-31 15:08:54

+0

哇。我已經嘗試過,它的工作原理。非常感謝。我必須誤解複製構造函數的工作原理。你能解釋一下嗎?我認爲next_最初會被初始化爲'0',因爲這是常規構造函數爲一個對象所做的事情。複製構造函數是否創建了一個新對象而沒有調用常規構造函數?所以當我正在做類似這樣的事情:「Node node1; // regular」,然後「Node node2 = node1; //複製」我用複製構造函數創建node2,我必須照顧所有初始化?沒有正規的構造函數?謝謝! – MCP 2012-07-31 17:08:48

1

你有一個列表和一個節點混淆的概念。您應該編寫一個管理節點序列的List類。你的Node析構函數或多或少是你的List析構函數應該看起來的,Node本身不需要析構函數。

特別是出錯的是,當你編寫的時候,你的Node析構函數遞歸調用自己delete temp;這會刪除節點序列的其餘部分,但是然後你的Node析構函數會循環並嘗試再次刪除它們。

+0

這就是昨天的感覺......雖然List類是如何管理節點的,但是沒有意義。它將如何包含節點?類中的結構?感謝您提供任何進一步的建議。 – MCP 2012-07-31 14:27:40

+0

最簡單的是指向第一個節點的指針。 'class List {public:... private:Node * head; }' – jahhaj 2012-07-31 18:23:29