析构函数,不会删除我的对象

时间:2012-04-18 18:38:07

标签: c++ list linked-list destructor

我有很大的问题 - 即我的析构函数不删除对象,在我的代码中,当我调用l3.~list();时,我将在main下面粘贴它只删除单链表(这很好),但它没有即使我在析构函数delete [] name;中说明,也要删除char * 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;
}

5 个答案:

答案 0 :(得分:5)

在调用析构函数之后调用任何方法会导致未定义的行为 - 它可能也可能不起作用,它可能会产生奇怪的结果。

此外,您不应该直接调用析构函数:

  • 当对象在堆栈上分配时,它会在作用域结束时自动销毁。 (范围是大括号之间的事物{}
  • 当使用new在堆上分配对象时,应使用delete销毁它。

答案 1 :(得分:1)

C ++析构函数与释放函数不同,就像你用C编写的那样。它们更好:在RAII idiom中,你的对象在你退出作用域的那一刻就被破坏了。这意味着你通常根本不需要关心释放资源:只需等到不再需要该对象(因为它无法访问),在这一点上它会被自动删除(包括调用析构函数,是的,这是安全地召唤它的唯一方式。所以编写良好的C ++在许多方面都与垃圾收集语言一样好,但没有一些缺点。

获得RAII优势的最简单方法是使用标准容器和智能指针。在您的情况下,将lista* next替换为std::unique_ptr<lista> next,将char* word替换为std::string word,一切正常,无需在所有中定义析构函数

答案 2 :(得分:0)

确保在销毁后不会错误地访问您的成员的一种方法是在删除后将所有指针设置为NULL。

这样,您可以放心,之后没有人可以访问您的敏感数据,因为您不再指向它。你可以再次调用析构函数而不会产生不良副作用,因为允许在NULL指针上调用delete并且什么都不做。

答案 3 :(得分:0)

这段代码存在很多错误,我不知道从哪里开始...

  • 使用std :: string
  • 使用std :: map将int值与字符串相关联。这几乎已经做了你想做的事。
  • 不要在析构函数中调用任何非新的东西。要删除某些内容,请使用delete / delete [],不要直接调用析构函数。如果您确实使用new,请使用管理std :: unique_ptr或std :: shared_ptr等对象来使用RAII习惯用法,以避免必须手动调用delete / delete []并编写异常安全代码

这是一个稍微改进的版本。请注意,没有一次调用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;
}

答案 4 :(得分:-1)

如果在删除对象后打印对象的内存状态,则在未分配新对象之前,您将看到值保持不变。为您的程序分配的内存只能更大。删除数据时,它们不会设置为“0”,只是为下一个alloc对象标记为空闲。

编辑:我的意思是如果你在空闲后创建一个未初始化值的新对象,他可以取回存储在内存中的旧值。