对于Accelerated C ++中的练习,我正在实现一个名为Str
的自定义字符串类。当底层存储容器是自定义向量(Vec
)时,一切正常,但现在我遇到了一个我不理解的奇怪的情境问题。
如果我通过显式调用Str
之类的构造函数创建一个新的Str newStr("some words");
对象,然后尝试使用cin >> newStr;
覆盖它,程序最终会崩溃,在调试器中给出一个SIGABRT当它到达Str
析构函数(只是delete[] data;
)时。
如果我创建一个新的空Str
然后使用cin
填充Str newStr; cin >> newStr;
,或者我使用cin
覆盖{ {1}}我使用Str
,只有在我尝试覆盖显式调用非默认构造函数的Str newStr = "some words";
时才会失败,即使此类型在被覆盖之前正确显示。
在这种情况下,如果我在创建/显示奇异行为Str
和使用Str
来改变它之间不创建任何新的Str
,那么另一个奇怪的事情实际上可以正常工作值。
cin
这表明您可以成功覆盖Str a = "Here is a";
Str b("And here is b");
cout << a << endl << b << endl;
Str c = "Finally we have c";
cout << c << endl;
cin >> c;
cout << c << endl << endl;
cin >> b;
cout << b << endl;
,但在尝试覆盖Str c
时崩溃。但是,这允许您覆盖Str b
并且程序成功完成:
b
Str a = "Here is a";
Str b("And here is b");
cout << a << endl << b << endl;
cin >> b;
cout << b << endl;
包含私人成员Str
,char* data
,int length, limit
和a
使用的构造函数为:
b
我也有Str::Str(const char* cp) {
limit = length = std::strlen(cp);
data = new char[length];
for (size_type i = 0; i != length; ++i)
data[i] = cp[i];
}
朋友,其实施是:
>>
我知道istream& operator>>(istream& is, Str& s) {
delete[] s.data;
s.length = s.limit = 0;
char c;
while (is.get(c) && isspace(c)) ;
if (is) {
do s.push_back(c);
while (is.get(c) && !isspace(c));
if (is)
is.unget();
}
return is;
}
在这个课程中可能是一个奇怪的函数,但即使使用push_back
很长cin
需要很多push_backs它也能正常工作。我已经尝试过几个小时调整类/运算符的不同部分并且难倒o_O
最后,我不确定为什么我的复制ctor在使用Str
语法的cout
初始化期间没有被调用(使用Str
s检查),即使它有效。
编辑,推送:
Str newStr = "blah";
答案 0 :(得分:2)
当您在输入操作符中delete[]
内存时,您需要确保data
成员设置为0
。如果你不这样做,那么你delete[]
delete[]
中已经push_back()
d的非空指针,你的程序会有未定义的行为:< / p>
istream& operator>>(istream& is, Str& s) {
delete[] s.data;
s.data = 0; // needed to keep your class invariants correct
s.length = s.limit = 0;
// ...
}
答案 1 :(得分:0)
构造函数没有为终止空字符分配空间(也没有存储它)。
我有一种感觉,将其改为:
Str::Str(const char* cp) {
limit = length = std::strlen(cp);
data = new char[length+1];
for (size_t i = 0; i != length; ++i)
data[i] = cp[i];
data[length] = '\0';
}
将解决您的问题。
在此期间,我建议稍微更改push_back
,以便始终添加终止空字符。
void Str::push_back(char c) {
if (length == limit) {
limit = (limit > 0 ? limit*2 : 1);
char* newData = new char[limit+1];
for (size_t i = 0; i < length; ++i)
newData[i] = data[i];
delete[] data;
data = newData;
}
data[length++] = c;
data[length] = '\0';
}
<强>更新强>
@Dietmar的答案是一个关键修复。不确定是否只需要这些。