C++ 当这些对象中的任何一个没有超出范围时,为什么调用析构函数?

C++ 当这些对象中的任何一个没有超出范围时,为什么调用析构函数?,c++,C++,当我从代码中删除析构函数时,输出符合我的要求,但如果我手动释放空间,程序就会变得疯狂:(请有人帮帮我,我正在使用code::Blocks IDE并在Linux mint OS中运行 #包括 #包括 使用名称空间std; 类str { char*p; 内伦; 公众: str(){ len=0; p=零; } str(const char*s); str(const-str&s); ~str(){ cout您没有重载赋值运算符。因此,同一指针被赋值并被删除两次,导致异常。您没有重载赋值运算符。因

当我从代码中删除析构函数时,输出符合我的要求,但如果我手动释放空间,程序就会变得疯狂:(请有人帮帮我,我正在使用code::Blocks IDE并在Linux mint OS中运行

#包括
#包括
使用名称空间std;
类str
{
char*p;
内伦;
公众:
str(){
len=0;
p=零;
}
str(const char*s);
str(const-str&s);
~str(){

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

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

您没有跳过r加载了赋值运算符。因此,同一指针被赋值并被删除两次,这导致了异常。

您没有重载赋值运算符。因此,同一指针被赋值并被删除两次,这导致了异常。

请阅读有关该指针的信息。 如果不声明赋值运算符,编译器将生成一个默认赋值运算符,它执行以下操作:

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

首先,上面的粗体文本适用于类中的char*p。 在运算符+函数中,tem是堆栈上的一个对象。当函数结束时,tem超出范围,并调用其析构函数。 因此,根据编译器生成的默认赋值运算符将string1的p赋值给tem的p,这意味着string1的p指向与tem的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将在调用其析构函数之前被复制

注意:

  • 当您删除析构函数时,它会工作,因为默认 编译器生成的析构函数不会取消分配 已分配内存,但这将泄漏内存,这是不好的
  • 您的代码中还有另一个主要缺陷。请使用删除[]进行以下操作: 释放数组
  • 阅读关于这个问题的文章。 如果不声明赋值运算符,编译器将生成一个默认赋值运算符,它执行以下操作:

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

    首先,上面的粗体文本适用于类中的char*p。 在运算符+函数中,tem是堆栈上的一个对象。当函数结束时,tem超出范围,并调用其析构函数。 因此,根据编译器生成的默认赋值运算符将string1的p赋值给tem的p,这意味着string1的p指向与tem的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将在调用其析构函数之前被复制

    注意:

  • 当您删除析构函数时,它会工作,因为默认 编译器生成的析构函数不会取消分配 已分配内存,但这将泄漏内存,这是不好的
  • 您的代码中还有另一个主要缺陷。请使用删除[]进行以下操作: 释放数组
  • 阅读关于这个问题的文章。 如果不声明赋值运算符,编译器将生成一个默认赋值运算符,它执行以下操作:

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

    首先,上面的粗体文本适用于类中的char*p。 在运算符+函数中,tem是堆栈上的一个对象。当函数结束时,tem超出范围,并调用其析构函数。 因此,根据编译器生成的默认赋值运算符将string1的p赋值给tem的p,这意味着string1的p指向与tem的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将在调用其析构函数之前被复制

    注意:

  • 当您删除析构函数时,它会工作,因为默认 编译器生成的析构函数不会取消分配 已分配内存,但这将泄漏内存,这是不好的
  • 您的代码中还有另一个主要缺陷。请使用删除[]进行以下操作: 释放数组
  • 阅读关于这个问题的文章。 当你这样做的时候