0

ダブルリンクリストのコピーコンストラクタ、デストラクタ、および代入演算子を取得しようとすると、多くの問題が発生しています。 私はクラスdlistとノードクラスを持っています。 Nodeクラスには、次および前のプライベートノードとデータフィールドが含まれます。私は本当に立ち往生しているし、私の人生はこれらを稼働させる方法を理解できない。誰かが何が間違っているかを指摘しても。時には私はsegの欠陥を取得し、私は大きな3つの変化に応じて、私はバックトレースを得る他の回。二重リンクリストBig Three

//Destructor 
template<class T> 
dlist<T>::~dlist(){ 
    node<T> *rmptr = head; 
    while(head != NULL && head != tail){ 
     head = head -> next(); 
     delete rmptr; 
    } 
} 

//Copy Constructor 
template <class T> 
dlist<T>::dlist(const dlist<T>& other) 
{ 
    if(other.head == NULL){ 
     head = new node<T>; 
     tail -> set_next(head); 
    } 
    else{ 
     head = new node<T>(other.head -> data()); 
     tail = new node<T>; 
     head -> set_next(tail); 
     tail -> set_previous(head); 
     node<T> *source = other.head -> next(); 
     node<T> *destination = head; 
     while(source != NULL && source != other.tail){ 
      tail -> set_next(new node<T>); 
      destination -> set_next(tail); 
      tail -> set_data(source -> data()); 
      tail = tail -> next(); 
      source = source -> next(); 
     } 
    } 

} 

//Assignment Operator 
template<class T> 
dlist<T>& dlist<T>::operator =(const dlist& other){ 

    if(this == &other){ 
     return *this; 
    } 
    node<T> * rmptr; 
    while(head != NULL){ 
     rmptr = head; 
     head = head -> next(); 
     delete rmptr; 
    } 
    head = tail = NULL; 

    node<T> *source, *destination; 
    if(other.head != NULL){ 
     head = new node<T>(other.head -> data()); 
     tail = new node<T>; 
     head -> set_next(tail); 
     tail -> set_previous(head); 
     node<T> *source = other.head -> next(); 
     node<T> *destination = head; 
     while(source != NULL && source != other.tail){ 
      tail -> set_next(new node<T>); 
      destination -> set_next(tail); 
      tail -> set_data(source -> data()); 
      tail = tail -> next(); 
      source = source -> next(); 
     } 
    } 

    return *this; 
} 
+2

正直なところ、コピーセマンティクスに到達する前でもこのコードにはいくつか問題があります。例:デストラクタは同じポインタ*( 'rmptr'、リストヘッドとして初期化されます)を繰り返し削除し、リストに割り当てられた残りのメモリをリークします(あなたがクラッシュしなかったと想定します)。 – WhozCraig

+0

へのご連絡ありがとうございます。それも参考になりました。 –

答えて

0

このコピー/割り当て/コンストラクタ/デストラクタパターンが(:)少なくとも私の基準では)古典である

  • まず、あなたがNULL(またはnullptr)にheadtailを設定する必要がありますへオブジェクトが作成され使用されなかった場合は、セグメンテーションを避けてください。これにより、デストラクタが初期化されていないheadを読み込むことが回避されます。 NULLデストラクタが何か有害な行為をしないようにする
  • 2番目:デストラクタ(もちろん)に割り当てられたユーティリティメソッドを作成し、割り当てられたオブジェクトを解放するための代入演算子(それ以外の場合はメモリリークが発生する)を作成します。同じコードをコピー/ペーストする必要はありません。そして私は最初にあなたの削除コードが大丈夫だと仮定していましたが、そうではありません。

    template<class T> 
    void dlist<T>::destroy() 
    { 
        node<T> *rmptr; 
        while(head != NULL && head != tail){ 
         rmptr = head; 
         head = head -> next(); 
         delete rmptr; 
    
        } 
        head = tail = NULL; // set head to NULL again 
    
    } 
    

    デストラクタだけで次のようになります:

    template<class T> 
    dlist<T>::~dlist(){ 
        destroy(); 
    } 
    
    • 第三には、使用copyユーティリティメソッドを作成

    destroyは次のようになります(WhozCraigコメントの助けを固定しました)コピーコンストラクタと代入演算子(彼らは多くの同じコードを共有し、コピー/ペーストする必要はありません)

copy方法は次のようになります。

template <class T> 
void dlist<T>::copy(const dlist<T>& other) 
{ 
    if(other.head == NULL){ 
     head = new node<T>; 
     tail -> set_next(head); 
    } 
    else{ 
     head = new node<T>(other.head -> data()); 
     tail = new node<T>; 
     head -> set_next(tail); 
     tail -> set_previous(head); 
     node<T> *source = other.head -> next(); 
     node<T> *destination = head; 
     while(source != NULL && source != other.tail){ 
      tail -> set_next(new node<T>); 
      destination -> set_next(tail); 
      tail -> set_data(source -> data()); 
      tail = tail -> next(); 
      source = source -> next(); 
     } 
    } 

} 

あなたは現在、非常に簡単にあなたのコピーコンストラクタ&代入演算子を実装することができます割り当てるとき

template<class T> 
dlist<T>::dlist(const dlist<T>& other) 
{ 
    copy(other); 
} 

//Assignment Operator 
template<class T> 
dlist<T>& dlist<T>::operator =(const dlist& other){ 

    if(this == &other){ 
     return *this; 
    } 
    destroy(); 
    copy(other); 

    return *this; 
} 

あなたは任意のメモリリークを持っていません。オブジェクトを別の "完全な"(別名割り当て済みの)オブジェクトに追加すると、割り当てられていない領域が解放されることはありません。headtailはです。

このパターンは非常に便利です。このような低レベルのクラスを作成しようとする訓練を受けていないコーダーは、常に同じメモリリーク/クラッシュ/コピーペーストのハードルで遭遇します。

+0

あなたの魂を祝福してください!どうもありがとうございます! –

+1

@KevinSwaggerを使用するか、[コピー/スワップイディオムモデル](https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom)を使用してください。 – WhozCraig

+0

@WhozCraigと私は私がスマートだと思った!それに感謝します。とても興味深い。 –

関連する問題