如何在析构函数中使用delete[]

Jim*_*ing 0 c++ delete-operator

我有以下用于实现Bucket课程的文件。但是我无法销毁s 生成的_str析构函数中的成员。我得到的错误是:Bucketoperator+

正常块后检测到堆损坏...CRT 检测到应用程序在堆缓冲区末尾后写入内存

添加两个Bucket对象后总是会出现问题,但是我在调​​试过程中检查了生成的字符串以及长度是否正确。

另外,如何访问函数_len中的属性operator>>以便分配新值?

头文件:

class Bucket
{
    friend ostream& operator<<(ostream& os, const Bucket& c);
    friend istream& operator>>(istream& is, const Bucket& c);
public:
    Bucket();
    Bucket(const String& str);
    Bucket(const char* str);
    ~Bucket();
    const Bucket operator+(const Bucket& s) const;
    const Bucket operator+(const char* s) const;
    const Bucket& operator=(const char* c);
    const bool operator==(const char* str);
private:
    char* _str;
    int _len;
}; 
Run Code Online (Sandbox Code Playgroud)

源文件:

Bucket::Bucket() {
    _len = 0;
    _str = new char[_len];
}

Bucket::Bucket(const Bucket& myBucket) {
    _len = myBucket._len;
    _str = new char[_len + 1];
    for (int i = 0; i < _len; i++)
        _str[i] = myBucket._str[i];
    _str[_len] = '\0';
}

Bucket::Bucket(const char* str) {
    _len = 0;
    for (int i = 0; str[i] != '\0'; i++) _len++;
    
    _str = new char[_len + 1];
    for (int i = 0; i < _len; i++)
        _str[i] = str[i];
    _str[_len] = '\0';
}

Bucket::~Bucket() {
    if (_len > 0) delete[] _str;
}

const Bucket Bucket::operator+(const Bucket& myBucket) const {
    String tempBucket;
    tempBucket._str = strcat(this->_str, myBucket._str);
    int len = 0;
    
    while (tempBucket._str[len] != '\0') len++;
    tempBucket._str[len] = '\0';
    tempBucket._len = len;
    return tempBucket;
}

const Bucket Bucket::operator+(const char* str) const {
    Bucket tempBucket;
    
    int len = 0;

    tempBucket._len = this->_len;

    for (int i = 0; str[i] != '\0'; i++) tempBucket._len++;

    tempBucket._str = strcat(tempBucket._str, str);

    tempBucket._str[len] = '\0';
    tempBucket._len = len;
    return tempBucket;
}

const Bucket& Bucket::operator=(const char* str) {
    if (this->_str == str) {
        return *this;
    }
    
    _len = 0;
    for (int i = 0; str[i] != '\0'; i++) _len++;

    _str = new char[_len + 1];
    for (int i = 0; i < _len; i++)
        _str[i] = str[i];
    _str[_len] = '\0';

    return *this;
}

const bool Bucket::operator==(const char* str) {
    int comp = strcmp(this->_str, str);
    if (comp == 0) {
        return true;
    }
    else {
        return false;
    }
}

ostream& operator<<(ostream& os, const Bucket& myBucket) {
    os << myBucket._str;
    return os;
}

istream& operator>>(istream& is, const Bucket& myBucket) {
    static char buffer[40];
    is >> buffer;

    int len = 0;
    for (size_t i = 0; buffer[i] != '\0'; i++) {
        myBucket._str[i] = buffer[i];
        len++;
    }
    myBucket._str[len++] = '\0';

    return is;
}
Run Code Online (Sandbox Code Playgroud)

主要的:

int main()
{
    Bucket b1("Hello, "); // This is deleted by the destructor
    Bucket b2(b1); // This is deleted by the destructor
    cout << b1 << b2 << endl; 
    b2 = "Dear ";  // Also works fine
    Bucket b3;
    cout << "Enter a name: ";
    cin >> b3; // Can't assign the _len attribute
    cout << b2 + b3 << ",";  // not destroyed
    Bucket b4(" Please write this sentence after pressing enter:\n");
    b2 = "We believe that ";
    cout << b4 + b2 << b1 << "and " << "Goodbye "  // not destroyed
        << (b1 == "Goodbye " ? "is " : "is not ") << "the same word!\n" <<
        endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 5

Bucket我发现您的代码的实现方式存在很多问题:

  • 的第二个参数operator>>需要是对非常量对象的引用,否则操作员在从 读取数据时无法修改该对象istream

  • 根据3/5/0 规则,缺少复制构造函数和复制赋值运算符,并且最好还缺少移动构造函数和移动赋值运算符。

  • 默认构造函数使用 分配内存new[],但由于_len为 0,析构函数不会释放该内存。_len > 0您需要在调用时删除对 的检查delete[]

  • 默认构造函数不会像其他构造函数那样以空终止分配的数组。

  • operator+按值返回一个新Bucket对象(应该如此),因此将该对象标记为多余的。const

  • 与返回bool的相同operator==。但是,它operator本身应该标记为const,因为它不会修改Bucket调用它的对象。

  • 两者operator+都使用strcat()不正确。重载Bucket正在修改 的内容this->str_,这是它不应该做的,更糟糕​​的this->_str是还没有被重新分配以增加其附加内容的能力myBucket._str。过char* 载也犯了类似的错误tempBucket.str_。您需要char[]为每个分配一个全新的数组tempBucket

  • Bucket的重载是operator+声明tempBucket为 asString而不是 as Bucket

  • operator=通过引用返回修改后的Bucket对象(应该如此),但该对象不应标记为.const

  • Bucket不公开_str从外部代码访问其成员的方法,因此签if (this->_str == str)operator==不可能是真实的。

  • operator=delete[]在用新内存替换旧_str内存之前,不会对旧内存进行处理char[]

  • operator>>不会对其buffer读入的内容执行任何边界检查。并且不会重新分配myBucket._str以适应 的内容buffer。并且,它正在计算 中的空终止符_len,而其他类方法都不会这样做。

话虽如此,尝试更像这样的事情:

class Bucket
{
    friend ostream& operator<<(ostream& os, const Bucket& rhs);
    friend istream& operator>>(istream& is, Bucket& rhs);
public:
    Bucket(size_t len = 0);
    Bucket(const Bucket& src);
    Bucket(Bucket&& src);
    Bucket(const char* str);
    Bucket(const char* str, size_t len);
    ~Bucket();

    Bucket operator+(const Bucket& rhs) const;
    Bucket operator+(const char* str) const;

    /*
    Bucket& operator=(const Bucket& rhs);
    Bucket& operator=(Bucket&& rhs);
    Bucket& operator=(const char* str);
    */
    Bucket& operator=(Bucket rhs);

    bool operator==(const Bucket& rhs) const;
    bool operator==(const char* rhs) const;

private:
    char* _str;
    size_t _len;

    void swap(Bucket &other);
    bool equals(const char* str, size_t len) const;
    Bucket concat(const char* str, size_t len) const;
};
Run Code Online (Sandbox Code Playgroud)
static size_t my_strlen(const char* str) {
    const char* start = str;
    if (str) while (*str != '\0') ++str;
    return (str - start);
}

Bucket::Bucket(size_t len) {
    _len = len;
    if (len > 0) {
        _str = new char[len + 1];
        _str[len] = '\0';
    }
    else {
        _str = nullptr;
    }
}

Bucket::Bucket(const Bucket& src)
    : Bucket(src._str, src._len) { }

Bucket::Bucket(Bucket&& src) : Bucket(0) {
    src.swap(*this);
}

Bucket::Bucket(const char* str)
    : Bucket(str, my_strlen(str)) { }
    
Bucket::Bucket(const char* str, size_t len) : Bucket(len) {
    if (str && len > 0) {
        for(size_t i = 0; i < len; ++i) {
            _str[i] = str[i];
        }
    }
}

Bucket::~Bucket() {
    delete[] _str;
}

void Bucket::swap(Bucket &other) {
    char *ptmp = _str;
    _str = other._str;
    other._str = ptmp;

    size_t itmp = _len;
    _len = other._len;
    other._len = itmp;
}

bool Bucket::equals(const char* str, size_t len) const {
    if (this->_len != len) return false;
    for(size_t i = 0; i < len; ++i) {
        if (this->_str[i] != str[i]) return false;
    }
    return true;
}

Bucket Bucket::concat(const char* str, size_t len) const {
    Bucket tempBucket(this->_len + len);
    for(size_t i = 0; i < this->_len; ++i) {
        tempBucket._str[i] = this->_str[i];
    }
    for(size_t i = this->_len, j = 0; j < len; ++i, ++j) {
        tempBucket._str[i] = str[j];
    }
    return tempBucket;
}

Bucket Bucket::operator+(const Bucket& rhs) const {
    return concat(rhs._str, rhs._len);
}

Bucket Bucket::operator+(const char* rhs) const {
    return concat(rhs, my_strlen(rhs));
}

/*
Bucket& Bucket::operator=(const Bucket& rhs) {
    if (this != &rhs) {
        Bucket(rhs).swap(*this);
    }
    return *this;
}

Bucket& Bucket::operator=(Bucket&& rhs) {
    Bucket(std::move(rhs)).swap(*this);
    return *this;
}

Bucket& Bucket::operator=(const char* rhs) {
    Bucket(rhs).swap(*this);
    return *this;
}
*/

Bucket& Bucket::operator=(Bucket rhs) {
    rhs.swap(*this);
    return *this;
}

bool Bucket::operator==(const Bucket& rhs) const {
    return equals(rhs._str, rhs._len);
}

bool Bucket::operator==(const char* rhs) const {
    return equals(rhs._str, my_strlen(rhs));
}

ostream& operator<<(ostream& os, const Bucket& rhs) {
    os.write(rhs._str, rhs._len);
    return os;
}

istream& operator>>(istream& is, Bucket& rhs) {
    /*
    string buffer;
    is >> buffer;
    rhs = buffer.c_str();
    return is;
    */
    char buffer[40];
    if (!is.get(buffer, 40)) buffer[0] = '\0';
    rhs = buffer;
    return is;
}
Run Code Online (Sandbox Code Playgroud)

话虽这么说,如果您可以使用标准 C++ 功能,例如 std::string,那么代码就会变得简单得多:

#include <string>

class Bucket
{
    friend ostream& operator<<(ostream& os, const Bucket& rhs);
    friend istream& operator>>(istream& is, Bucket& rhs);
public:
    Bucket() = default;
    Bucket(const Bucket& src) = default;
    Bucket(Bucket&& src) = default;
    ~Bucket() = default;

    Bucket(const std::string& str);

    Bucket operator+(const Bucket& rhs) const;

    Bucket& operator=(const Bucket& rhs) = default;
    Bucket& operator=(Bucket&& rhs) = default;

    bool operator==(const Bucket& rhs) const;

private:
    std::string _str;
};
Run Code Online (Sandbox Code Playgroud)
Bucket::Bucket(const std::string str) : _str(str) { }

Bucket Bucket::operator+(const Bucket& rhs) const {
    return Bucket(this->_str + rhs._str);
}

bool Bucket::operator==(const Bucket& rhs) const {
    return (this->_str == rhs._str);
}

ostream& operator<<(ostream& os, const Bucket& rhs) {
    os.write << rhs._str;
    return os;
}

istream& operator>>(istream& is, Bucket& rhs) {
    is >> rhs._str;
    return is;
}
Run Code Online (Sandbox Code Playgroud)