2017-05-11 12 views
0

私は一方向リストを実装しようとしています。 m3 = m1 + m2コマンドがmain関数で2倍になるまで、すべてが完璧に機能します。私がデバッグしていたとき、オーバーロードされた=演算子では、破棄が発生した後、o1オブジェクトに割り当てられた値が消えていたことに気付きました。デストラクタ、または演算子に何か問題があるかどうかは分かりません。オーバーロード演算子=、クラス内の面倒なデストラクタC++

#include <iostream> 
using namespace std; 

    template <class T> 
    class Element; 

    template <class T> 
    class List{ 
     friend class Element<T>; 
     Element<T> *head; 
    public: 
     List(){ 
      cout<<"konstruktor"<<endl; 
      head=NULL; 
     } 
     ~List() { 
      Element<T> *tmp = head; 
      cout << "destruktor" << endl; 
      while (tmp) { 
       //tmp = tmp->next; 
       delete head; 
       head = tmp; 
      } 
     } 
     friend istream &operator>>(istream &p, List<T> &o1){ 
      Element<T>* new_ele; 
      Element<T>* it; 
      it=o1.head; 
      new_ele=new Element<T>; 
      p>>new_ele->value; 
      new_ele->next=NULL; 
      if (o1.head==NULL){ 
       o1.head=new_ele; 
      } 
      else{ 
       while (it->next!=NULL){ 
        it=it->next; 
       } 
       it->next=new_ele; 
      } 
      return p; 
     } 
     friend ostream &operator<<(ostream &s, List<T> &o1){ 
      Element<T>* it; 
      it=o1.head; 
      while(it){ 
       s<<it->value<<" "; 
       it=it->next; 
      } 
      return s; 
     } 
     List <T> &operator=(const List<T> &o1){ 
      if (this==&o1){ 
       return *this; 
      } 
      Element<T> *it1, *it2, *itc; 
      this->~List();//this is the where everything goes haywire 
      itc=head; 
      it1=o1.head; 
      while(it1){ 
       itc=new Element<T>; 
       if (!head) head=it1; 
       itc->next=NULL; 
       itc->value=it1->value; 
       it1=it1->next; 
       itc=itc->next; 
      } 
      return *this; 
     } 

     List<T> &operator+(List<T> &o1){ 
      if(o1.head==NULL){ 
       return *this; 
      }else if(head==NULL){ 
       return o1; 
      } 
      static List<T> res=*this; 
      Element<T> *it; 
      it=res.head; 
      while(it->next) { 
       it = it->next; 
      } 
      Element <T> *o1_it=o1.head; 
      while(o1_it){ 
       Element<T> *copy; 
       copy=new Element<T>; 
       copy->next=NULL; 
       copy->value=o1_it->value; 
       it->next=copy; 
       it=it->next; 
       o1_it=o1_it->next; 
      } 
      return res; 
     } 

     int length_list(){ 
      Element<T> *it; 
      int count_elements=0; 
      it=head; 
      while(it->next){ 
       count_elements++; 
       it=it->next; 
      } 
      return count_elements; 
     } 

     void bubblesort_List(){ 
      Element<T> *it; 
      for(int i=0; this->length_list() > i;i++){ 
       it = head; 
       while (it->next) { 
        if (it->next->value < it->value) { 
         T tmp = it->value; 
         it->value = it->next->value; 
         it->next->value = tmp; 
        } 
        it = it->next; 
       } 
      } 
     } 
    }; 

    template <class T> 
    class Element{ 
     friend class List<T>; 
     friend istream &operator>>(istream &p, List<T> &o1); 
     friend ostream &operator<<(ostream &s, List<T> &o1); 

     Element<T> *next; 
     T value; 
    public: 
     Element(){ 
      next=NULL; 
     } 
    }; 
    int main(){ 

     List<int> m1, m2, m3; 

     cin>>m1>>m1>>m1; 
     cin>>m2; 
     m3=m1+m2; 
     m3=m1+m2; 
     cout<<m3<<endl; 

     return 0; 
    } 
+4

[mcve]にコードを減らすと、問題が見つかる可能性があります。もしそうでなければ、あなたはここで尋ねる合理的な質問をするでしょう。 –

+1

デストラクタを明示的に呼び出さないでください。まれな例外がありますが、あなたの人生でそれらを満たすことはほとんどありません。 – Slava

答えて

-1

つの主要な問題

  • コール明示的に〜一覧を呼び出すことはありません、デストラクタを呼び出すために削除します。ここでは

    は、コードがあります。ただ、free_listか何かそれを呼び出すと、あなたのデストラクタが壊れている

  • 頭の上にそれを呼び出す、それはあなたが欲しい正しく

メモリを解放していない:

void free_list (Element<T> * head) { 
Element<T> *tmp = head; 
while (tmp != null) { 
    head = tmp.next; 
    delete tmp; 
    tmp = head; 
}} 
0
this->~List(); 

これは、オブジェクトを破壊します。デストラクタを実行するだけではありません。

オブジェクトが破棄された後、そのストレージは残りますが、にはオブジェクトがありません。あたかもオブジェクトがあるかのようにストレージと対話すると、未定義の動作が発生します。

ヘルパー関数にデストラクタの身体を動かし

clear()と呼ばれる:

はそれを修正:

clear() { 
     std::cout << "clear" << std::endl; 
     while (head) { 
      Element<T>* tmp = head; 
      head=head->next; 
      delete tmp; 
     } 
    } 

とあなたの~List()は単にclear()ことにします。

次に、operator=を修正してください。

List& operator=(List&&o) { 
     if (this==&o) 
     return *this; 
     clear(); 
     head = o.head; 
     o.head = nullptr; 
     return *this 
    } 
    List& operator=(const List &o) { 
     if (this== &o) 
     return; 
     *this = List(o); // call operator=(List&&) using a copy of o 
     return *this; 
    } 
    List(List&& o): 
     head(o.head) 
    { 
     o.head = nullptr; 
    } 
    List():head(nullptr) {} 
    // all of the work goes on here: 
    List(List const& o):List() 
    { 
     Element<T>* src = o.head; 
     Element<T>** dest = &head; 
     while(src) { 
     *dest = new Element<T>; 
     (*dest)->value = src->value; 
     (*dest)->next = nullptr; 
     src = src->next; 
     dest = &((*dest)->next); 
     } 
    } 

私はより単純な機能を実行するためにすべてを連鎖しました。

=(&&)および(&&)(移動割り当ておよび移動構成)コピーheadをコピーしてソースを消去します。これは少量の重複コードです。

=(const&)(copy-assign)は=(&&)(move-assign)と(const&)(copy-construct)を使用します。ノードをコピーするビジネスは難しい。一つの状況でそれを行う。空のインスタンスへのコピーは、すでに存在するインスタンスへのコピーよりも簡単です。

(const&)は、作業を行う唯一のものです。ここでは、リンクされたリストの末尾にポインタを置くポインタと、次の要素を追加するポインタを保持します。

次に、次の要素のコピーをスプライスし、テールと次の要素ポインタを更新します。

関連する問題