2012-04-18 5 views
-1

私は大きな問題を持っています - つまり、私のデストラクタは、私がl3.~list();を呼び出すときに私がメインに下に貼り付けるコードでオブジェクトを削除しません。私のデストラクタであると言っても、char * nameは削除されませんdelete [] name;。どんなアイデアが間違っていますか?デストラクタは、私のオブジェクトを削除しません

ここにコードがあります。未定義の動作でデストラクタの結果を呼び出した後、任意のメソッドを呼び出す

#include <iostream> 
#include <cstdlib> 
#include <string> 
using namespace std; 

class list{ 

    struct lista 
    { 
     int num; 
     char* word; 
     lista* next; 
    }; 
    lista* head; 
    char* name; 
    public: 
    list(char* name1){head=NULL;name=new char[strlen(name1)+1];strcpy(name,name1);} 
    char getChar(int key, int index); 
    void setChar(int key, int index, char c); 
    void insert(int number,char* txt); 
    void remove(int number); 
    void print(); 
    list(const list &o); 
    list& operator=(const list &x); 
    ~list(); 
}; 
void list::insert(int number,char* txt){ 
    lista* ptr,*tmp; 
    ptr=head; 
    lista* newlista=new lista; 
    newlista->num=number; 
    newlista->next=NULL; 
    newlista->word= new char[strlen(txt)+1]; 
    strcpy(newlista->word,txt); 
    if(head==NULL){ 
     head=newlista; 
     newlista->next=NULL; 
    } 
    else while(ptr!=NULL){ 
     if(strcmp(txt,ptr->word)>=0){ 
      if(ptr->next!=NULL && strcmp(txt,ptr->next->word)<=0) 
      { 
       tmp=ptr->next; 
       ptr->next=newlista; 
       newlista->next=tmp; 
       break; 
      } 
      else if(ptr->next!=NULL && strcmp(txt,ptr->next->word)>0) 
       ptr=ptr->next; 
      else 
      { 
       //next is empty 
       ptr->next=newlista; 
       break; 
      } 
     } 
     else{ 
      //txt mniejszy niz w 1szym elemencie 
      newlista->next=head; 
      head=newlista; 
      break; 
     }  
    } 
    return; 
} 

void list::print(){ 
    cout<<name<<";"<<endl; 
    lista *druk; 
    druk=head; 
    while(druk!=NULL){ 
     cout<<"txt: "<<druk->word<<" | "<<"num: "<<druk->num<<endl; 
     druk=druk->next; 
    } 
    cout<<endl; 
    return; 
} 


void list::remove(int number){ 
    if(head==NULL) 
     return; 
    if(head->num==number){ 
     lista* ptr=head; 
     head=head->next; 
     delete [] ptr->word; 
     delete ptr; 
     return; 
    } 
    lista* ptr=head; 
    while(ptr->next!=NULL && ptr->next->num!=number) 
     ptr=ptr->next; 
    if(ptr->next==NULL){ 
     cout<<number<<" element not found"<<endl; 
     return; 
    } 
    lista* todelete=ptr->next; 
    ptr->next=todelete->next; 
    delete [] todelete->word; 
    delete todelete; 
    return; 
} 
list::list(const list &o) 
{ 
    lista *xtr = o.head; 
    head=NULL;// bez tego nie działa 
    lista *etr=head;// nastawic etr na head? 
    while (xtr) 
    { 
     lista* ntr = new lista; 
     if (!ntr) 
     { 
      cerr << "list::CopyConstructor: Allocation memory failure!"; 
      cerr << endl; 
      break; 
     } 
     ntr->num = xtr->num; 
     ntr->word= new char[strlen(xtr->word)+1]; 
     strcpy(ntr->word,xtr->word); 
     ntr->next = NULL; 
     if (head) 
      etr->next = ntr;  
     else 
      head = ntr; 
     etr = ntr; // keep track of the last element in *this 
     xtr = xtr->next; 
    } 
    name = new char[strlen(o.name)+5]; 
    strcpy(name,o.name); 
    strcat(name,"Copy"); 
} 

list& list::operator=(const list &x) 
{ 
    if(this==&x) 
     return *this; 
    lista *etr=head; 
    while(etr) // removing list from this 
    { 
     etr=etr->next; 
     delete head; 
     head=etr; 
    } 
    lista *xtr=x.head; 
    while(xtr) 
    { 
     int copied=xtr->num; 
     lista *ntr= new lista; 
     ntr->word=new char[strlen(xtr->word)+1]; 
     if (!ntr) 
     { 
      cerr << "list::operator=: Allocation memory failure!" << endl; 
      break; 
     } 
     ntr->num=copied; 
     strcpy(ntr->word,xtr->word); 
     ntr->next=NULL; 
     if (!head) 
      head = ntr; 
     else 
      etr->next = ntr; 

     etr = ntr; // keep track of the last element in *this 
     xtr = xtr->next; 
    } 
    char *name=new char[strlen(x.name)+1]; 
    strcpy(name,x.name); 
    return *this; 
} 

list::~list() 
{ 
    cout<<"Object with name:"<<name<<" destroyed!"<<endl; 
    delete [] name; 
    lista *dtr=head; 
    while(dtr) // removing lista from this 
    { 
     dtr=dtr->next; 
     delete [] head->word; 
     delete head; 
     head=dtr; 
    } 

} 
void f(); 
void f(){ 
    list o("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 
    o.insert(4,"kazio"); 
    o.insert(100,"312jh31io2"); 
    o.insert(34,"kz31231azio"); 
    o.insert(1020,"123213312jh31io2"); 
    o.insert(213123,"z3213io"); 
    o.insert(1100,"zdrf312jh31io2"); 
    o.print(); 
} 
int main(){ 
    list l1("lista1"); 
    l1.insert(5,"Endian"); 
    l1.insert(7,"Endianness"); 
    l1.insert(100,"Hexediting"); 
    l1.insert(34,".mil"); 

    l1.print(); 
    list l2(l1); // usage of CC - the same as list l2=l1; 
    l2.print(); 
    l2.remove(5); 
    l2.print(); 
    l1.print(); 

    list l3("asajnment"); 
    l3=l2=l1; 
    l3.print(); 
    l2.print(); 
    f(); 
    l3.print(); 
    l3.~list(); // here i use destructor on l3 
    l3.print(); // l3 is being printed with weird name, even though it should be destroyed 
    getchar(); 
    return 0; 
} 
+8

なぜデストラクタを直接呼びますか?あなたはそれをするべきではありません。 –

+0

が正しく動作するかどうかを確認しますか? –

+5

これを行うことは、最初は適切ではないため、できません。 – leftaroundabout

答えて

5

- それは、あるいは仕事とまたそれは奇妙な結果を生成することができます場合があります。スコープが終了したときに

オブジェクトがスタックに割り当てられている
  • が、それは自動的に破棄されます。

    また、あなたは直接デストラクタを呼び出すことになっていません。 (スコープは中括弧の間のものです{}

  • オブジェクトがヒープ上に割り当てられた場合は、newを使用して、オブジェクトをdeleteで破棄する必要があります。
+1

何もしないと、未定義の動作になります。オブジェクトが有効範囲外になると、デストラクタは自動的に呼び出されるため、この場合は2回呼び出されます。悪いニュース。 –

+2

また、静的な記憶期間(つまり、関数やクラスの外部で宣言されているか、 'static'と宣言されている)を持つオブジェクトに対してデストラクタを直接呼び出さないでください。これらは、プログラムが終了すると自動的に破棄されます。それを直接呼び出す唯一の時間は、オブジェクトが配置 'new'で作成された場合です。 –

1

C++のデストラクタは、Cで記述したように割り当て解除関数と似ていません。RAII idiomでは、スコープを終了する瞬間にオブジェクトが破棄されます。つまり、通常はリソースを解放する必要はありません。オブジェクトが不要になるまで待つだけで(アクセスできないため)、自動的に削除されます(デストラクタの呼び出し、yesそれが安全に呼び出される唯一の方法です)。だからよく書かれたC++は、ガベージコレクション言語と同じくらい多くの点で優れていますが、いくつかの欠点はありません。

RAIIの利点を得る最も簡単な方法は、標準のコンテナとスマートポインタを使用することです。あなたの場合、とをstd::string wordと置き換えてください。デストラクタを定義する必要はありません。はすべてです。

0

あなたのメンバーが破壊後に誤ってアクセスされないようにする方法の1つは、すべてのポインタを削除後にNULLに設定することです。

これで、あなたがもう指していないので、後で誰も機密データにアクセスできないことが保証されます。そして、NULLポインタでdeleteを呼び出すことが許可され、何もしないので、悪い副作用なしにデストラクタを再度呼び出すことができます。

+0

私はこれが彼の問題と非常に関係していると信じていますが、方法と理由を説明する必要があります –

+0

その他の回答は既に説明済みです。破壊後にオブジェクトにアクセスしないようにすることをお勧めします。だから私はもう一度説明する必要はありませんでした。プログラムを破壊した後にプログラムがオブジェクトにアクセスする状況がある場合は、安全対策を講じることができます。 –

-1

オブジェクトのメモリ状態を削除した後で印刷すると、新しいオブジェクトを割り当てない限り、その値が維持されます。あなたのプログラムに割り当てられるメモリは、もっと大きくなることができます。データを削除すると、それらは '0'に設定されず、次のallocオブジェクトに対して空きとしてマークされます。

EDIT:初期化されていない値を空けた直後に新しいオブジェクトを作成すると、メモリに保存されている古い値を取り戻すことができます。私が開始する場所がわからない、このコードでそんなに間違ってあり

+0

私はそれが正しいとは思わない。プログラムに割り当てられたメモリがダウンする可能性があります。仮想メモリの仕組みについては混乱しているようです。 –

+0

私はそれを経験しました。私は公式の文書でそれを読むこともできました: http://www.cplusplus.com/reference/clibrary/cstdlib/free/ 多分私はよく分かりません:/ 効果的にsegfaultを得ることができます。 – blaize

+0

メモリが解放された後、それはUBにアクセスすることですが、実際にはOSにリリースされることもありますが、通常は何が起こったのかはあなたの説明です。 –

0

...

  • 使用のstd ::文字列
  • を持つint型の値を関連付けるためのstd ::マップを使用文字列。これは、あなたが欲しいものを既にかなり前倒しするでしょう。
  • new'dではないもののデストラクタを呼び出さないでください。何かを削除するにはdelete/delete []を使い、デストラクタを直接呼び出さないでください。あなたが新しい使用する場合は、手動で/削除呼び出し[]削除し、ここで

がある例外安全なコードの書き込みをすることを避けるために、このようなのstd :: unique_ptrをかのstd :: shared_ptrのように管理するオブジェクトを使用してRAIIイディオムを使いますやや改良されたバージョン。 new/deleteの呼び出しは一度もないことに注意してください。

#include <iostream> 
#include <string> 
#include <map> 
#include <cstdio> 

class list 
{ 
public: 
    explicit 
    list(std::string n) : name(n) {} 

    ~list() { std::cout << "~list:" << name << std::endl; } 

    void list::insert(int number, std::string const& txt){ 
     items.insert(std::make_pair(number,txt)); 
    } 

    void list::remove(int number){ 
     items.erase(number); 
    } 

    void print(){ 
     std::cout << name << ";" << std::endl; 
     for(Items::const_iterator it = items.begin(), end = items.end(); it != end; ++it ) 
     { 
      std::cout << "num: " << it->first << " | " << "txt: " << it->second << std::endl; 
     } 
     std::cout << std::endl; 
    } 

private: 
    typedef std::map<int,std::string> Items; 
    Items items; 
    std::string name; 
}; 

int main() 
{ 
    list l1("lista1"); 
    l1.insert(5, "Endian"); 
    l1.insert(7, "Endianness"); 
    l1.insert(100, "Hexediting"); 
    l1.insert(34, ".mil"); 
    // extra scope so the destructor of l2 is called before call to getchar 
    { 
     list l2(l1); 
     l2.remove(5); 
     l2.print(); 
    } 
    l1.print(); 

    getchar(); 
    return 0; 
} 
関連する問題