实现operator+=时使用delete[](堆损坏)
我几个小时以来一直在试图解决这个问题,但我已经无计可施了。如果有人能在我做错的时候告诉我,我一定会很感激。
我编写了一个简单的类来模拟字符串的基本功能。该类的成员包括一个字符指针data(它指向动态创建的字符数组)和一个整数strSize(它保存字符串的长度,没有终止符。
)我正在使用 new 和 delete,我已经实现了复制构造函数和析构函数。当我尝试实现 operator+= 时,出现了问题。 LHS 对象正确构建新字符串 - 我什至可以使用 cout 打印它 - 但是当我尝试在析构函数中释放数据指针时出现问题:我在指向的内存地址处收到“正常块后检测到堆损坏”通过析构函数尝试释放的 data 数组。
这是我完整的课程和测试程序:
#include <iostream>
using namespace std;
// Class to emulate string
class Str {
public:
// Default constructor
Str(): data(0), strSize(0) { }
// Constructor from string literal
Str(const char* cp) {
data = new char[strlen(cp) + 1];
char *p = data;
const char* q = cp;
while (*q)
*p++ = *q++;
*p = '\0';
strSize = strlen(cp);
}
Str& operator+=(const Str& rhs) {
// create new dynamic memory to hold concatenated string
char* str = new char[strSize + rhs.strSize + 1];
char* p = str; // new data
char* i = data; // old data
const char* q = rhs.data; // data to append
// append old string to new string in new dynamic memory
while (*p++ = *i++) ;
p--;
while (*p++ = *q++) ;
*p = '\0';
// assign new values to data and strSize
delete[] data;
data = str;
strSize += rhs.strSize;
return *this;
}
// Copy constructor
Str(const Str& s)
{
data = new char[s.strSize + 1];
char *p = data;
char *q = s.data;
while (*q)
*p++ = *q++;
*p = '\0';
strSize = s.strSize;
}
// destructor
~Str() { delete[] data; }
const char& operator[](int i) const { return data[i]; }
int size() const { return strSize; }
private:
char *data;
int strSize;
};
ostream& operator<<(ostream& os, const Str& s)
{
for (int i = 0; i != s.size(); ++i)
os << s[i];
return os;
}
// Test constructor, copy constructor, and += operator
int main()
{
Str s = "hello"; // destructor for s works ok
Str x = s; // destructor for x works ok
s += "world!"; // destructor for s gives error
cout << s << endl;
cout << x << endl;
return 0;
}
编辑:加速 C++ 问题 12-1。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
下面的代码块使 p 指向数组旁边。
您在复制构造函数中使用的更好(且安全)的解决方案:
Following chunk of code makes p pointed beside the array.
Better (and safe) solution you have used in copy constructor:
这里已经有很多很好的答案,但值得将 Valgrind 作为解决此类问题的工具。如果您可以访问 *nix 盒子,Valgrind 工具可以成为真正的救星。
只是为了向您展示,这是我通过它编译和运行程序时得到的结果:
您可以看到它精确地指出了此处其他答案指出的行(第 36 行附近)。
There are already a bunch of good answers here, but it's worth plugging Valgrind as a tool for solving exactly this sort of problem. If you have access to a *nix box, the Valgrind tools can be a real lifesaver.
Just to show you, here's what I got when compiling and running your program through it:
You can see that it pinpointed the lines that the other answers here pointed out (near line 36).
使用与复制构造函数中使用的类似的习惯用法:
Use an idiom similar to what you used in the copy constructor:
您已经有两个答案指向导致您垃圾堆的特定错误。假设这是家庭作业或其他形式的练习(否则我们都会因为你编写自己的字符串类而对你大喊大叫),这里还有一些需要咀嚼的东西适合您:
例如,代替
char* p = str; // 新数据
,您可以直接编写char* new_data = str;
。您可以只编写
do_frgl();
,而不是//do frgl
后跟一大块代码。如果函数是内联的,则对生成的代码没有任何影响,但对代码的读者来说却有很大的不同。std
中的所有内容转储到全局命名空间。 这根本不是一个好主意。我会像瘟疫一样避免包含您的标头。Str::Str(const char*)
构造函数为同一个字符串调用std::strlen()
两次。应用程序代码应根据需要尽可能快,库代码<另一方面,如果您不知道它以哪个应用程序结束,则应该尽可能快。您正在编写库代码。
size()
成员函数是否会返回负值?如果不是,为什么它是有符号整数?Str s1, s2; s1=s2?
Str str("abc"); std::cout<
(如果遇到此问题的任何人都可以想到更多提示,请随意扩展它。)
You already have two answers pointing at the specific error that made you trash the heap. Assuming this is homework or some other form of exercise (otherwise we'd all be yelling at you for writing your own string class), here's a few more things to chew on for you:
For example, instead of
char* p = str; // new data
, you could just writechar* new_data = str;
.Instead of
//do frgl
, followed by a chunk of code, you could just writedo_frgl();
. If the function is inlined, it makes no difference for the resulting code, but a lot of difference to readers of the code.std
dumped into the global namespace. That's not a good idea at all. I'd avoid including your header like the plague.Str::Str(const char*)
constructor callsstd::strlen()
twice for the same string.Application code should be as fast as needed, library code, on the other hand, where you don't know which application it ends in, should be as fast as possible. You're writing library code.
size()
member function ever return a negative value? If not, why is it a signed integer?Str s1, s2; s1=s2
?Str str("abc"); std::cout<<str[1];
(If anyone coming across this can think of more hints, feel free to expand this.)