当显式调用非默认ctor时,覆盖自定义字符串失败

时间:2014-06-09 04:29:24

标签: c++ string cin overwrite

对于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; 包含私人成员Strchar* dataint length, limita使用的构造函数为:

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";

2 个答案:

答案 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的答案是一个关键修复。不确定是否只需要这些。