Изменение размера массива символов не всегда работает

В пользовательском строковом классе Str У меня есть функция c_str() который просто возвращает приватный член char* data как const char* c_str() const { return data; }, Это работает, когда вызывается после создания нового Str но если я тогда перезаписать Str с помощью 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 просто «б» на cin >> b; затем выводит «b» + немного мусора. Но если я пытаюсь изменить его на «bb», он обычно работает, и если я изменяю его на что-то более длинное, чем «это 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() может выводить любой мусор памяти.

0

Решение

На основе push_back() в вопросе а c_str() в комментарии нет гарантии, что C-строка вернулась из c_str() имеет нулевое значение Так как char const* не знает длину строки без нулевого терминатора, это источник проблемы!

При выделении небольших объектов памяти вы, вероятно, возвращаете один из небольших объектов памяти, ранее использовавшихся вашим строковым классом, который содержит ненулевые символы, в результате чего напечатанный символ выглядит так, как если бы он был длиной до первого найденного нулевого байта. При выделении больших кусков вы, кажется, возвращаете «свежую» память, которая все еще содержит нулевой символ, создавая ситуацию, как будто все в порядке.

Есть два основных способа решения этой проблемы:

  1. Добавить нулевой терминатор перед возвратом char const* от c_str(), Если вам сейчас нет дела до многопоточности, это можно сделать в c_str() функция. В тех случаях, когда многопоточность имеет значение, вероятно, плохая идея делать какие-либо мутации в const функции-члены, поскольку они будут представлять гонки данных. Таким образом, стандартные строковые классы C ++ добавляют нулевой терминатор в одну из операций мутирования.
  2. Не поддерживают c_str() Функция вообще, но реализовать оператор вывода для вашего строкового класса. Таким образом, нулевое завершение не требуется.
3

Другие решения