如何在析构函数中使用 delete[]
How to use delete[] in destructor
我有以下用于实现 Bucket
class 的文件。但是,我无法在 operator+
生成的 Bucket
的析构函数中销毁 _str
成员。我得到的错误是:
heap corruption detected after normal block...CRT detected that the application wrote to memory after end of heap buffer
问题总是在添加两个 Bucket
对象后出现,但是我在调试过程中检查了生成的字符串以及长度是否正确。
此外,如何访问 operator>>
函数中的 _len
属性以分配新值?
头文件:
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;
};
源文件:
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] = '[=11=]';
}
Bucket::Bucket(const char* str) {
_len = 0;
for (int i = 0; str[i] != '[=11=]'; i++) _len++;
_str = new char[_len + 1];
for (int i = 0; i < _len; i++)
_str[i] = str[i];
_str[_len] = '[=11=]';
}
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] != '[=11=]') len++;
tempBucket._str[len] = '[=11=]';
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] != '[=11=]'; i++) tempBucket._len++;
tempBucket._str = strcat(tempBucket._str, str);
tempBucket._str[len] = '[=11=]';
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] != '[=11=]'; i++) _len++;
_str = new char[_len + 1];
for (int i = 0; i < _len; i++)
_str[i] = str[i];
_str[_len] = '[=11=]';
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] != '[=11=]'; i++) {
myBucket._str[i] = buffer[i];
len++;
}
myBucket._str[len++] = '[=11=]';
return is;
}
主要:
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;
}
我发现您的 Bucket
代码的实施方式存在很多问题:
operator>>
的第二个参数需要是对non-const对象的引用,否则运算符无法修改从 istream
.
读取数据时的对象
缺少复制构造函数和复制赋值运算符,最好还有移动构造函数和移动赋值运算符,根据 Rule of 3/5/0。
默认构造函数使用 new[]
分配内存,但由于 _len
为 0,析构函数不会释放该内存。您需要在调用 delete[]
.
时删除对 _len > 0
的检查
默认构造函数不是 null-terminating 分配的数组,其他构造函数正在这样做。
operator+
正在返回一个新的 Bucket
对象 按值 (应该是),因此将该对象标记为 const
是多余的。
同bool
即operator==
returns。但是,operator
本身应标记为 const
,因为它不会修改调用它的 Bucket
对象。
两个 operator+
都错误地使用了 strcat()
。 Bucket
重载正在修改 this->str_
的内容,这是不应该做的,更糟糕的是 this->_str
还没有重新分配以增加其附加 [=34] 内容的能力=]. char*
重载与 tempBucket.str_
犯了类似的错误。您需要为每个 tempBucket
.
分配一个全新的 char[]
数组
operator+
的 Bucket
重载将 tempBucket
声明为 String
而不是 Bucket
.
operator=
通过引用 返回修改后的 Bucket
对象 (应该是),但该对象不应该标记为 const
.
Bucket
没有公开从外部代码访问其 _str
成员的方法,因此 if (this->_str == str)
无法签入 operator==
永远是真的。
operator=
不是 delete[]
在用新的 char[]
.
替换旧的 _str
内存之前
operator>>
未对其读入的 buffer
执行任何边界检查。并且 re-allocating myBucket._str
不适合内容buffer
。并且,它正在计算 _len
中的空终止符,其他 class 方法的 none 也是如此。
综上所述,试试这样的东西:
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;
};
static size_t my_strlen(const char* str) {
const char* start = str;
if (str) while (*str != '[=11=]') ++str;
return (str - start);
}
Bucket::Bucket(size_t len) {
_len = len;
if (len > 0) {
_str = new char[len + 1];
_str[len] = '[=11=]';
}
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] = '[=11=]';
rhs = buffer;
return is;
}
也就是说,如果您可以使用标准的 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;
};
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;
}
我有以下用于实现 Bucket
class 的文件。但是,我无法在 operator+
生成的 Bucket
的析构函数中销毁 _str
成员。我得到的错误是:
heap corruption detected after normal block...CRT detected that the application wrote to memory after end of heap buffer
问题总是在添加两个 Bucket
对象后出现,但是我在调试过程中检查了生成的字符串以及长度是否正确。
此外,如何访问 operator>>
函数中的 _len
属性以分配新值?
头文件:
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;
};
源文件:
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] = '[=11=]';
}
Bucket::Bucket(const char* str) {
_len = 0;
for (int i = 0; str[i] != '[=11=]'; i++) _len++;
_str = new char[_len + 1];
for (int i = 0; i < _len; i++)
_str[i] = str[i];
_str[_len] = '[=11=]';
}
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] != '[=11=]') len++;
tempBucket._str[len] = '[=11=]';
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] != '[=11=]'; i++) tempBucket._len++;
tempBucket._str = strcat(tempBucket._str, str);
tempBucket._str[len] = '[=11=]';
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] != '[=11=]'; i++) _len++;
_str = new char[_len + 1];
for (int i = 0; i < _len; i++)
_str[i] = str[i];
_str[_len] = '[=11=]';
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] != '[=11=]'; i++) {
myBucket._str[i] = buffer[i];
len++;
}
myBucket._str[len++] = '[=11=]';
return is;
}
主要:
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;
}
我发现您的 Bucket
代码的实施方式存在很多问题:
读取数据时的对象operator>>
的第二个参数需要是对non-const对象的引用,否则运算符无法修改从istream
.缺少复制构造函数和复制赋值运算符,最好还有移动构造函数和移动赋值运算符,根据 Rule of 3/5/0。
默认构造函数使用
时删除对new[]
分配内存,但由于_len
为 0,析构函数不会释放该内存。您需要在调用delete[]
._len > 0
的检查默认构造函数不是 null-terminating 分配的数组,其他构造函数正在这样做。
operator+
正在返回一个新的Bucket
对象 按值 (应该是),因此将该对象标记为const
是多余的。同
bool
即operator==
returns。但是,operator
本身应标记为const
,因为它不会修改调用它的Bucket
对象。两个
分配一个全新的operator+
都错误地使用了strcat()
。Bucket
重载正在修改this->str_
的内容,这是不应该做的,更糟糕的是this->_str
还没有重新分配以增加其附加 [=34] 内容的能力=].char*
重载与tempBucket.str_
犯了类似的错误。您需要为每个tempBucket
.char[]
数组operator+
的Bucket
重载将tempBucket
声明为String
而不是Bucket
.operator=
通过引用 返回修改后的Bucket
对象 (应该是),但该对象不应该标记为const
.Bucket
没有公开从外部代码访问其_str
成员的方法,因此if (this->_str == str)
无法签入operator==
永远是真的。
替换旧的operator=
不是delete[]
在用新的char[]
._str
内存之前operator>>
未对其读入的buffer
执行任何边界检查。并且 re-allocatingmyBucket._str
不适合内容buffer
。并且,它正在计算_len
中的空终止符,其他 class 方法的 none 也是如此。
综上所述,试试这样的东西:
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;
};
static size_t my_strlen(const char* str) {
const char* start = str;
if (str) while (*str != '[=11=]') ++str;
return (str - start);
}
Bucket::Bucket(size_t len) {
_len = len;
if (len > 0) {
_str = new char[len + 1];
_str[len] = '[=11=]';
}
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] = '[=11=]';
rhs = buffer;
return is;
}
也就是说,如果您可以使用标准的 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;
};
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;
}