-1

我有一个大问题 - 即我的析构函数没有删除对象,在我的代码中,当我调用l3.~list();它时我将粘贴在 main 的下面只删除单链表(这很好),但它不会删除 char* 名称,甚至虽然我在我的析构函数中说明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;
}
4

5 回答 5

5

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

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

  • 当对象在堆栈上分配时,它会在作用域结束时自动销毁。(范围是大括号之间的东西{}
  • 当对象在堆上分配时,使用new,它应该使用 销毁delete
于 2012-04-18T18:46:06.770 回答
1

C++ 析构函数不像您可能在 C 中编写的释放函数。它们更好:在RAII 惯用语中,您可以在对象退出作用域的那一刻对其进行销毁。这意味着您通常根本不必关心释放资源:只需等到不再需要该对象(因为它无法访问),此时它会自动删除(包括调用析构函数,是的,这是可以安全调用它的唯一方法)。编写良好的 C++ 在许多方面都与垃圾收集语言一样好,但没有它们的一些缺点。

获得 RAII 好处的最简单方法是使用标准容器和智能指针。在您的情况下,lista* nextstd::unique_ptr<lista> nextchar* word替换,一切都很好,根本std::string word不需要定义析构函数。

于 2012-04-18T18:56:03.930 回答
1

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

  • 使用 std::string
  • 使用 std::map 将 int 值与字符串相关联。这几乎已经可以满足您的需求了。
  • 不要为任何不是新的东西调用析构函数。要删除某些内容,请使用 delete/delete[] 并且不要直接调用析构函数。如果您确实使用 new,请使用 RAII 习惯用法来管理对象,例如 std::unique_ptr 或 std::shared_ptr 以避免手动调用 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;
}
于 2013-02-14T21:32:04.777 回答
0

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

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

于 2012-04-18T18:56:44.277 回答
-1

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

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

于 2012-04-20T07:36:25.220 回答