繁体   English   中英

析构函数不会破坏对象

[英]Destructor does not destroy objects

我已经编写了一个小程序,但是主析构函数无法正常工作。 这是程序的代码:

#include<iostream.h>

class citizen {
private:
    char* name;
    char* nationality;
public:             
    citizen(char* name, char* nationality) {
        this->name = name;
        this->nationality = nationality;
    }                  

    citizen(const citizen &obj) {
        name = obj.name;
        nationality = obj.nationality;
    }        

    void display() {
        cout << "Name: " << name << endl;
        cout << "Nationality: " << nationality << endl;
    }

    ~citizen() { 
        if(name){
            delete[]name;
        }
        if(nationality) {
            delete []nationality;                          
        }        
    }       
};

main() {
   citizen obj1("Ali", "Pakistani");
   obj1.display();
   { 
      citizen obj2 = obj1;                 
   }
   obj1.display();
   system("pause");
}

我所知道的是,在将obj1状态分配给obj2 main函数中,这两个位置现在都指向相同的内存区域。 而代码citizen obj2 = obj1; 在两个花括号之间。

   { 
      citizen obj2 = obj1;                 
   }

因此,在执行第二个花括号后, obj2应该销毁并删除变量namenationality 当我调用obj1.display(); 第二次它应该在屏幕上显示垃圾。

但是obj1仍在打印我在构造函数中提供的确切名称,即使它不是应该如此。

请解释此行为。

您的delete[]调用未定义的行为,因为您正试图破坏字符串文字。 什么都可能发生。

即使您自己分配了内存,您仍然会遇到未定义的行为,因为您将尝试访问已删除的内存:

obj1.display();
{ 
   citizen obj2 = obj1;                 
}
obj1.display();  // ILLEGAL

因为您没有定义赋值运算符,所以将使用编译器生成的赋值运算符,它仅将指针分配给相同的内存-您先销毁然后尝试访问的内存。

复制构造函数只复制指针(如果没有提供自己的指针,则隐式指针会这样做),这意味着两个对象都将尝试删除相同的数组。 另外,您正在将指针设置为指向字符串文字,这些文字绝对不能删除。 您只能删除使用new创建的对象。 一个简单的解决方案是将内存管理委托给一个旨在正确执行此操作的类:

std::string name;
std::string nationality;

现在,您无需费心使用自己的析构函数,复制构造函数或复制分配运算符; 另外,您的课程也可以在C ++ 11中正确移动。

如果您喜欢自己处理内存问题,则需要构造函数分配新的缓冲区并在其中复制内容。 请谨慎对待异常安全性,因为您试图在一个类中处理两个单独的动态资源,而这总是错误的根源。 您还需要一个拷贝分配运算符(按照3的规则 ),为了提高效率,您还可以考虑一个move构造函数和move-assignment运算符。

同样,可能值得更新到本世纪的一种语言版本。 <iostream.h>大约十五年来一直不是标准头文件。

该代码有误。

     if(name){
              delete[]name;
     }
     if(nationality){                          
              delete []nationality;                          
     }   

您正在使用new运算符删除尚未在堆上分配的内容。

也有人指出,该字符串相关的错误,但我认为你正在做一个更根本的错误: delete 破坏的东西。*; 它只是释放内存以供重用,并调用相关的析构函数。 这意味着在delete操作之后通常完全有可能使用删除的对象,而不会导致垃圾回收。

*-在某些实现中,在__DEBUG模式下,它将在释放的内存上加盖戳记,以允许您发现这些错误,但这不是标准的一部分。

您应该只delete使用new operator在类中dynamically allocated的内存块

citizen(char* aname, char* anationality){

     size_t nameSize = strlen(aname)
     size_t nationalitySize = strlen(anationality)

     this->name = new char[nameSize];
     this->nationality = new char[nationalitySize];

     strcpy(this->name, aname, nameSize);
     this->name[nameSize ] = NULL;

     strcpy(this->nationality , anationality , nationalitySize);
     this->nationality [nationalitySize] = NULL;
}

如果在constructor创建内存,则在destructor中将其删除。 并且由于您有一些分配,那么您应该实现一个copy constructor ,WHICH创建一个内存并在= operator的右侧复制数据

最后的想法是,如果不能处理指针以避免memory leaks ,最好使用字符串对象

很高兴您的第二次展示电话可以正常工作。

正如Jack Aidley指出的那样,delete并不从字面上删除值,只是将内存区域标记为可用。 因此,如果没有其他应用程序分配和修改该释放区域,则先前的值可能会保留在那里。 此外,删除后,您仍然保留指向该地址的指针。

总而言之,您正在访问具有旧值的相同内存区域。 但这很幸运,因为该区域未被任何人修改。

为防止此类错误,应始终将NULL分配给未使用的指针,以便下次尝试访问它们时遇到访问冲突错误。 一些编译器(例如MSVC)用签名值(例如0xDDDDDD)重写释放的内存,以便在调试过程中可以轻松地发现问题。 查看此答案以获取详细信息

最后, delete应该与new匹配,否则行为是不确定的,因此再次很幸运。 我什至无法运行您的应用程序并显示结果。 它不断崩溃,并给出内存错误。

谢谢大家。 我已替换此构造函数代码

citizen(char* name, char* nationality) {
    this->name = name;
    this->nationality = nationality;
}        

用这个代码

citizen(char* name, char* nationality){ 
   this->name = new char[strlen(name)+1]; 
   strcpy(this->name, name); 
   this->nationality = new char[strlen(nationality)+1]; 
    strcpy(this->nationality, nationality); 
} 

最终效果很好。 谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM