当任何这些对象没有超出范围时,为什么要调用析构函数?

时间:2015-03-07 17:36:21

标签: c++

当我从代码中删除析构函数时,输出就像我想要的那样但是如果我手动释放空间程序会变得疯狂:(请有人帮助我,我使用Code :: Blocks IDE并运行在Linux mint OS enter image description here

enter image description here

#include<iostream>
#include<cstring>
using namespace std;
class str
{
    char *p;
    int len;
public:
    str() {
        len=0;
        p=NULL;
    }
    str(const char *s);
    str(const str &s);
    ~str() {
        cout<<" Distructor Called ";
        delete p;
    }
    friend str operator+(const str &s,const str &t);
    friend bool operator<=(const str &s,const str &t);
    friend void show(str &s);
};

str::str(const char *s)
{
    len=strlen(s);
    p=new char[len+1];
    strcpy(p,s);
}
str::str(const str &s)
{
    len=s.len;
    p=new char[len+1];
    strcpy(p,s.p);
}

void show(str &s)
{
    cout<<s.p;
}
str operator+(const str &s,const str &t)
{
    str tem;
    tem.len=s.len+t.len;
    tem.p=new char[tem.len+1];
    strcpy(tem.p,s.p);
    strcat(tem.p,t.p);
    return tem;
}
bool operator<=(const str &s,const str &t)
{
    if(s.len<=t.len)
        return true;
    else
        return false;
}

int main()
{
    str s1="New ";
    str s2="York";
    str s3="Delhi";
    str string1,string2,string3;
    string1=s1;
    string2=s1+s2;
    string3=s1+s3;

    cout<<"\nString1 = ";
    show(string1);
    cout<<"\nString2 = ";
    show(string2);
    cout<<"\nString3 = ";
    show(string3);
    cout<<"\n\n";
    if(string1<=string2) {
        show(string1);
        cout<<" Smaller Than ";
        show(string2);
        cout<<"\n";
    } else {
        show(string3);
        cout<<"Smaller Than ";
        show(string1);
        cout<<"\n";
    }
    return 0;
}

2 个答案:

答案 0 :(得分:2)

了解Rule of Three。 如果未声明赋值运算符,编译器将生成默认值,执行以下操作:

  

从赋值运算符的参数的相应成员中分配所有对象的成员,调用对象的类类型成员的复制赋值运算符,并执行所有非类型的明确赋值(例如int或指针) )数据成员

首先,上面的粗体文字适用于您班级中的char * p。 在operator +函数中,tem是堆栈上的对象。当函数结束时,tem超出范围,并调用其析构函数。 所以会发生什么是string1的p根据编译器生成的默认赋值运算符分配tem的p,这意味着string1的p指向与tem的p相同的内存位置,在它超出范围后被释放!因此,string1没有预期的值。稍后,当string1超出范围并调用其析构函数时,第二次在同一内存位置调用delete,从而导致显示错误。同样,对于string2。

如果你像这样重载赋值运算符,情况会很好:

void str::operator=(const str&s) {
    delete[] p;
    len=s.len;
    p=new char[len+1];
    strcpy(p,s.p);
}

在这种情况下,tem的p将在调用析构函数之前被复制。

注意:

  1. 当您删除析构函数时,它会起作用,因为它是默认值 编译器生成的析构函数不会释放 分配内存,但这会泄漏内存,这是不好的。
  2. 您的代码中还有另一个主要缺陷。使用删除[] 解除分配数组。

答案 1 :(得分:1)

您没有重载赋值运算符。因此,相同的指针被分配并被删除两次导致异常。