Я знаю, что строковые объекты не заканчиваются нулем, но почему это должно работать?
std::string S("Hey");
for(int i = 0; S[i] != '\0'; ++i)
std::cout << S[i];
Таким образом, конструктор также копирует нулевой терминатор, но не увеличивает длину? Почему это беспокоит?
Таким образом, конструктор также копирует нулевой терминатор, но не увеличивает длину?
Как вы знаете, что std::string
не содержит нулевой символ (и здесь не копируется нулевой символ).
Дело в том, что вы используете std::basic_string::operator[]
, Согласно C ++ 11, станд :: basic_string :: Оператор [] вернет нулевой символ, когда указанный индекс эквивалентен size()
,
Если
pos == size()
, ссылка на символ со значениемCharT()
(нулевой символ) возвращается.Для первой (неконстантной) версии поведение не определено, если этот символ изменен на любое значение, кроме
charT()
,
std::string
хранит свои данные внутри себя в виде C-строки с нулевым символом в конце, но при обычном использовании не позволяет получить доступ к нулевому терминатору.
Например, если я назначу значение «Hello, World!» для строки внутренний буфер будет выглядеть так:
std::string myString("Hello, World!");
// Internal Buffer...
// [ H | e | l | l | o | , | | W | o | r | d | ! | \0 ]
// ^ Null terminator.
В этом примере нулевой терминатор НЕ был скопирован с конца строкового литерала, но добавлен внутри std::string
,
Как @songyuanyao упоминает в своем ответе, результатом этого является то, что myString[myString.size()];
возвращается '\0'
,
Так почему же std::string
назначить нулевой терминатор в конце строки? Это, конечно, не должно поддерживать один, потому что вы можете добавить '\0'
в строку, и она включена в строку:
std::string myString;
myString.size(); // 0
myString.push_back('\0');
myString.size(); // 1
Причиной такого поведения является поддержка std::string::c_str()
функция. c_str()
функция требуется для возврата с нулевым символом в конце const char *
, Самый эффективный способ сделать это — просто вернуть указатель на внутренний буфер, но для этого внутренний буфер должен содержать нулевой символ-терминатор в конце строки. Начиная с C ++ 11, строки требуется включить нулевой терминатор для поддержки этого.
Постскриптум Хотя это и не является частью вашего вопроса, следует отметить, что цикл из вашего вопроса может НЕ возвращать полную строку, если ваша строка содержит нулевые символы:
std::string S("Hey");
S.push_back('\0');
S.append("Jude");
for(int i = 0; S[i] != '\0'; ++i)
std::cout << S[i];
// Only "Hey" is printed!