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

时间:2014-09-04 06:57:25

标签: c++ operator-overloading destructor

#include<iostream>
using namespace std;


class MyString{

private:
 char *str=new char[10];

public:
    MyString(){*str='\0';}           //default constructor
    MyString(char *s){               //parameterized constructor
    str=s;
}

private:
int length(char* s){
    int i=0;
    while(s[i]!='\0')
        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]!='\0'){
        j=0;
        start++;
        while(s.str[j]!='\0'){
            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 返回null。但是,当我不使用析构函数时,我得到了预期的输出。任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

主要问题是Operater-返回一个由默认复制构造函数复制的本地对象 - 默认复制构造函数将s3指向temp MyString的完全相同的内存/缓冲区,当该temp被破坏时,它消除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)

你需要一个析构函数,这就是你需要其他人的线索。原因就像我说的那样 - 默认情况下你会免费获得一个复制构造函数,但如果有资源点,它只会使所有内容指向相同的内容,但是你不能在不影响其他人的情况下删除它。 / p>

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

temp[j] = '\0';

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

如果你还记得我把你的析构函数拉出来,那就是我所做的改变。

析构函数也有一个问题,如果你使用new来创建一个数组,比如

char* c = new char[10];

然后你需要以一种新的方式删除它作为一个数组,如下所示:

delete [] c;

接下来你要研究的是你的MyString结构是如何发生的。如果你单步执行,你会看到str成员变为new'd - 这意味着它将一个有效的地址保存到你可以使用的缓冲区中 - 但是如果使用了MyString(char * s)构造函数,那么它就是字面意思只取这个s的新地址,并使str保持该地址 - 这意味着指向有效缓冲区的旧地址丢失,并且新内存的缓冲区不能被释放。这是一个泄漏。您可以使用我添加的构造函数中的strcpy_s策略将MyString(char * s)中s指向的内容复制到new'd缓冲区中。这将在代码中产生巨大的积极影响。

并且不要为那里的所有精英主义者打扰 - 他们中的许多人天生就做倒立,所以他们无法看到与新手做出诚实努力的关系。

以下是完整的修改代码:

#include<iostream>
using namespace std;

class MyString{

private:
    char *str = new char[10];

public:
    MyString(){ *str = '\0'; }           //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] != '\0')
            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] = '\0';
        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] != '\0'){
            j = 0;
            start++;
            while (s.str[j] != '\0'){
                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;
}