c++ 中的自串联

Self-Concatenation in c++

我正在处理一个字符串 class,其中 int 代表长度,char* 代表数据。我已经覆盖了 += 运算符,它工作得很好,除非你尝试自连接,例如:

String s1 = "Hello";
s1 += s1;
cout << s1;

这个returns:À$p 或者其他奇怪的字符。这是我的相关代码:

#include <iostream>
#include <cstring>
#include "assert.h"
using namespace std;

class String{
    public:
    int len;
    char *str;

    String()
    :len(0), str(nullptr){}

    String(char const* S)
    :len(strlen(S)), str(new char[len +1]){
        assert(S != 0);
        strcpy(str, S);
    }

    ~String(){
        delete[]str;
    }

    char* data() const{
        return this->str;
    }

    String operator +=(String const &S){
        int n = this->len + S.len;
        char * p = new char[n+1];
        strcpy(p + len, S.str);
        len = n;
        str = p;
        return *this;
    }
};

std::ostream& operator <<(ostream& os, String const& str){
    return os << str.data();
}

int main()
{
    String g1 = "Hello";
    g1 += g1;
    cout << g1;
    return 0;
}

这段代码有几个问题。首先,回顾一下 Rule of Three/Five/Zero is.

现在,实际operator+=存在三个问题:

  1. 您实际上并没有将字符串的初始部分复制到 p。你只是在复制后半部分。您需要执行以下操作:

    memcpy(p, str, len);
    memcpy(p + len, S.str, S.len);
    
  2. 您没有清理旧内容。当你写 str = p; 时,你只是泄露了 str 指向的内存。你需要写:

    delete [] str;
    

    在你做那个作业之前。

  3. 您返回的是一个会立即销毁的临时文件。缺少复制构造函数(请参阅初始点)意味着您正在破坏 g1 的缓冲区,然后当您尝试 main() 末尾时出现双自由损坏错误 delete[] 再说一遍。这个问题可以通过编写一个有效的复制构造函数来解决,但是 operator+= 不应该返回一个临时的 - 它应该返回一个引用:

    String& operator+=(String const& S) { ... }