<<运算符重载在使用析构函数时返回 null

<< operator overloading returning null on using destructor

本文关键字:lt null 析构函数 返回 运算符 重载      更新时间:2023-10-16
#include<iostream>
using namespace std;

class MyString{
private:
 char *str=new char[10];
public:
    MyString(){*str='';}           //default constructor
    MyString(char *s){               //parameterized constructor
    str=s;
}
private:
int length(char* s){
    int i=0;
    while(s[i]!='')
        i++;
return i;
}
char* delchar(char* s,int count,int start){
    int i,j=0;
    char *temp= new char[10];
    for(i=start;i<start+count;i++){
        s[i]=' ';
    }
    for(i=0;i<length(s);i++){
        if(s[i]!=' ')
            temp[j++]=s[i];
    }
    s=temp;
    return s;
}
public:
MyString operator-(MyString s){
    int i=0,j=0,count=0,start=-1;/* i to iterate the first string,j to iterate the     second string*/
    MyString temp;              /*  count to count the matched characters ,start to know the starting index*/
    temp.str=str;
    while(temp.str[i]!=''){
        j=0;
        start++;
        while(s.str[j]!=''){
            if(temp.str[i]==s.str[j]){
                count++;
                i++;
                j++;
                if(count==length(s.str)){//checks if the count
                    temp.str=delchar(temp.str,count,start);
                    i=i-count;
                    start=i-1;
                    count=0;
                }
            }
            else{
                i++;
                count=0;
                break;
            }
        }
    }
    return temp;
}
~MyString(){
    delete str;
}
friend ostream &operator<<(ostream &stream,MyString& s){
    stream<<s.str<<endl;
    return stream;
}
};
int main(){
char *p= new char[20];
char *q= new char[10];
cin>>p;
cin>>q;
MyString s1(p);
MyString s2(q);
MyString s3;
s3=s1-s2;
cout<<s3;
delete p;
delete q;
return 0;
}

上面的代码重载了 - 运算符。它尝试从主字符串中减去子字符串,例如input1:joshmathews input2:josh output:mathews。我正在尝试将输出存储在新的 MyString 对象 s3 中。当我使用如上所示的析构函数时,输出 s3返回空值。但是当我不使用析构函数时,我会得到预期的输出。谁能帮忙?

主要问题是 Operatorr- 返回一个由默认复制构造函数复制的本地对象 - 该默认复制构造函数将 s3 指向临时 MyString 完全相同的内存/缓冲区,当该临时被破坏时,它会清除 s3 正在使用的内存。

这称为悬空指针。您可以在此处阅读更多内容:http://en.wikipedia.org/wiki/Dangling_pointer#Cause_of_wild_pointers

下面的代码是我所做的更改,以使程序执行并返回有效结果,同时完成而没有错误。需要明确的是,此更改版本,运行时错误或没有运行时错误存在问题,但这将有助于阐明一些要点。

当你定义一个分配内存的类型时,你真的开始做一些不免费的事情了。我在下面修改的版本完全摆脱了析构函数,所以实际上它会泄漏内存,直到程序结束。析构函数无效,因此删除它允许程序完成。但这将是通常你不应该接受的事情之一。

我添加了一个复制构造函数和一个复制赋值运算符:

MyString(const MyString& s) {
    strcpy_s(str, 10, s.str);
}
MyString& operator=(const MyString& s) {
    strcpy_s(str, 10, s.str);
    return *this;
}

请注意这两个strcpy_s。正在做的是从参数中复制字符串,而不仅仅是尝试指向与参数完全相同的地址完全相同的字符串。如果参数在您的版本中被破坏,它会清除一些内存,因此我们可以只接受默认的复制构造函数,因为默认情况下它们是指向相同胆量的浅拷贝。这是分配内存的负担之一 - 你需要在你的析构函数的~和~一些构造函数中照顾到这一点。这被称为"三法则":

如果需要自己显式声明析构函数、复制构造函数或复制赋值运算符,则可能需要显式声明所有三个运算符。

这里有一个关于三法则的维基百科链接:http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming(

你需要一个析构函数,所以这就是你需要其他的线索。原因正如我所说 - 默认情况下,您可以免费获得一个复制构造函数,但是如果有点是资源,它只会使所有内容都指向相同的胆量,但是您无法删除一个而不会影响其他人。

另外,在delchar中,我在底部添加了这一行:

temp[j] = '';

字符串必须始终以 null 结尾,并且您只将实际的字母字符复制到 temp 中,因此如果没有空字符,strcpy 就不知道在哪里结束。

如果你还记得我拉出了你的析构函数,那么这些就是我所做的更改。

析构函数也有一个问题,因为如果您使用 new 创建数组,例如

char* c = new char[10];

然后,您需要以指示 in 是新数组的方式删除它,如下所示:

delete [] c;

接下来你应该研究的是你的MyString结构是如何发生的。如果你逐步完成,你会看到str成员得到新的 - 这意味着它将一个有效的地址保存到你可以使用的缓冲区中 - 但是如果使用MyString(char *s(构造函数,它实际上只是接受s的新地址,并使str保留该地址 - 这意味着指向有效缓冲区的旧地址丢失, 并且无法释放新内存的缓冲区。所以这是一个泄漏。您可以使用我添加的构造函数中的strcpy_s策略将 MyString(char *s( 中的 s 所指向的内容的上下文复制到新的缓冲区中。这将对代码产生巨大的积极影响。

不要理会所有的精英主义者——他们中的许多人天生就是倒立的,所以他们看不到与新手诚实地努力联系起来。

以下是完整的更改代码:

#include<iostream>
using namespace std;
class MyString{
private:
    char *str = new char[10];
public:
    MyString(){ *str = ''; }           //default constructor
    MyString(char *s){               //parameterized constructor
        str = s;
    }
    MyString(const MyString& s) {
        strcpy_s(str, 10, s.str);
    }
    MyString& operator=(const MyString& s) {
        strcpy_s(str, 10, s.str);
        return *this;
    }
private:
    int length(char* s){
        int i = 0;
        while (s[i] != '')
            i++;
        return i;
    }
    char* delchar(char* s, int count, int start){
        int i, j = 0;
        char *temp = new char[10];
        for (i = start; i<start + count; i++){
            s[i] = ' ';
        }
        for (i = 0; i<length(s); i++){
            if (s[i] != ' ')
                temp[j++] = s[i];
        }
        temp[j] = '';
        s = temp;
        return s;
    }
public:
    MyString operator-(MyString s){
        int i = 0, j = 0, count = 0, start = -1;/* i to iterate the first string,j to iterate the     second string*/
        MyString temp;              /*  count to count the matched characters ,start to know the starting index*/
        temp.str = str;
        while (temp.str[i] != ''){
            j = 0;
            start++;
            while (s.str[j] != ''){
                if (temp.str[i] == s.str[j]){
                    count++;
                    i++;
                    j++;
                    if (count == length(s.str)){//checks if the count
                        temp.str = delchar(temp.str, count, start);
                        i = i - count;
                        start = i - 1;
                        count = 0;
                    }
                }
                else{
                    i++;
                    count = 0;
                    break;
                }
            }
        }
        return temp;
    }
    ~MyString(){
        //delete str;
    }
    friend ostream &operator<<(ostream &stream, MyString& s){
        stream << s.str << endl;
        return stream;
    }
};
int main(){
    char *p = new char[20];
    char *q = new char[10];
    cin >> p;
    cin >> q;
    MyString s1(p);
    MyString s2(q);
    MyString s3;
    s3 = s1 - s2;
    cout << s3;
    delete p;
    delete q;
    return 0;
}