2016-11-21 6 views
4

Я знаю, что строковые объекты не являются нулевыми, но почему это должно работать?Do std :: strings end в ' 0' при инициализации строковым литералом?

std::string S("Hey"); 
for(int i = 0; S[i] != '\0'; ++i) 
    std::cout << S[i]; 

Таким образом, конструктор также копирует нулевой ограничитель, но не увеличивает длину? Почему это беспокоит?

+0

'станд :: string' не пахнет, как C. –

+0

Проверьте это: http: // stackoverflow.com/questions/39725183/difference-between-string-empty-and-string0-0/39725242 –

+2

Я снова открыл вопрос, потому что OP знал о 'std :: string', не имеет нулевого конца, но путается о поведении' std :: строка :: оператор [] '. – songyuanyao

ответ

6

Таким образом, конструктор также копирует нулевой ограничитель, но не увеличивает длину?

Как вы знаете, std::string не содержит нулевой символ (и здесь он не копирует нулевой символ).

Дело в том, что вы используете std::basic_string::operator[]. Согласно C++ 11, std::basic_string::operator[] вернет нулевой символ, если указанный индекс эквивалентен size().

Если pos == size(), ссылка на символ со значением CharT() (нулевой символ) возвращается.

Для первой (не константной) версии поведение не определено, если этот символ изменен на любое значение, отличное от charT().

2

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(). Для возврата const char * требуется функция c_str(). Самый эффективный способ сделать это - просто вернуть указатель на внутренний буфер, но для этого внутренний буфер должен содержать символ нулевого терминатора в конце строки. Поскольку C++ 11, строки требуется, чтобы включить нулевой ограничитель для поддержки этого.

P.S. Хотя это и не часть вашего вопроса, то следует отметить, что цикл из вашего вопроса может не возвращать полную строку, если строка содержит нулевые символы:

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!