0

在一个名为的自定义字符串类中,Str我有一个函数c_str()将私有成员返回char* dataconst char* c_str() const { return data; }. 这在我创建新文件后调用时有效,Str但如果我随后覆盖Strusing cin,则调用c_str()它有时有效,但如果我比原来cin的更大,则总是有效。Str

Str b("this is b");
cout << b.c_str() << endl;

cin >> b;
cout << b.c_str() << endl;

这里第一个b.c_str()有效,但如果我尝试在线路上更改Str b为“b”,cin >> b;那么它会输出“b”+一些垃圾。但是,如果我尝试将其更改为“bb”,它通常会起作用,如果我将其更改为比“this is b”更长的东西,它总是会起作用。

这很奇怪,因为我的 istream 运算符(它是友好的)完全解除分配Str并最终为它读取的每个字符分配一个仅大 1 个字符的新字符数组(只是为了看看它是否可以工作,它没有)。因此,在读取其他内容后返回数组似乎会返回data设置它的新数组。

相关功能:

istream& operator>>(istream& is, Str& s) {
    delete[] s.data;
    s.data = nullptr;
    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;
}

void Str::push_back(char c) {
    if (length == limit) {
        ++limit;
        char* newData = new char[limit];

        for (size_type i = 0; i != length; ++i)
            newData[i] = data[i];

        delete[] data;
        data = newData;
    }
    data[length++] = c;
}

push_back()像这样,数组的容量永远不会超过它所拥有的容量,所以我看不出我怎么能c_str()输出任何内存垃圾。

4

1 回答 1

3

根据push_back()问题中的 和c_str()评论中的 ,不能保证返回的 C 字符串c_str()是空终止的。由于 achar const*不知道没有空终止符的字符串的长度,这就是问题的根源!

分配小内存对象时,您可能会取回字符串类以前使用的小内存对象之一,该对象包含非空字符,导致打印的字符看起来好像是找到第一个空字节的长度。当分配更大的块时,您似乎会取回仍然包含空字符的“新鲜”内存,使情况看起来好像一切正​​常。

基本上有两种方法可以解决这个问题:

  1. char const*在返回from之前添加一个空终止符c_str()。如果你现在不关心多线程,这可以在c_str()函数中完成。在多线程很重要的情况下,在const成员函数中进行任何突变可能是一个坏主意,因为这会引入数据竞争。因此,C++ 标准字符串类在变异操作之一中添加了空终止符。
  2. 根本不支持c_str()函数,而是为您的字符串类实现输出运算符。这样,就不需要空终止。
于 2014-06-09T21:49:13.670 回答