Законно ли перезаписывать нулевой терминатор std :: string?

В C ++ 11 мы знаем, что std::string гарантированно будет как смежным, так и нулевым (или, более педантично, завершенным charT()который в случае char нулевой символ 0).

Мне нужен этот C API, который заполняет строку указателем. Он записывает всю строку + нулевой терминатор. В C ++ 03 я всегда был вынужден использовать vector<char>потому что я не мог предположить, что string был смежным или нулевым. Но в C ++ 11 (при условии надлежащего соответствия basic_string класс, который все еще сомнительный в некоторых стандартных библиотеках), я могу.

Или я могу? Когда я делаю это:

std::string str(length);

Строка будет выделять length+1 байтов, с последним заполненным нулевым терминатором. Это хорошо. Но когда я передаю это в C API, он собирается написать length+1 персонажи. Это собирается переписать нулевой терминатор.

По общему признанию, это собирается переписать нулевой терминатор с нулевым символом. Хорошие шансы, что это будет работать (действительно, я не могу себе представить, как это не может Работа).

Но мне все равно, что «работает». Я хочу знать, согласно спецификации, можно ли перезаписывать нулевой терминатор нулевым символом?

35

Решение

LWG 2475 сделал это действительным, отредактировав спецификацию operator[](size()) (вставленный текст выделен жирным шрифтом):

В противном случае возвращает ссылку на объект типа charT со значением
charT()где модификация объекта на любое значение, кроме charT()
приводит к неопределенному поведению.

8

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

К сожалению, это UB, если я правильно интерпретирую формулировку (в любом случае, это не разрешено):

§21.4.5 [string.access] p2

Возвращает: *(begin() + pos) если pos < size()в противном случае ссылка на объект типа T со значением charT(); указанное значение не должно быть изменено.

(Редакционная ошибка, которая говорит T не charT.)

.data() а также .c_str() в основном указывают на operator[] (§21.4.7.1 [string.accessors] p1):

Возвращает: Указатель p такой, что p + i == &operator[](i) для каждого i в [0,size()],

25

Согласно спецификации, перезаписывая завершающий NUL должно быть неопределенное поведение.
Таким образом, правильно было бы выделить length+1 символы в строке, передать строковый буфер в C API, а затем resize() вернуться к length:

// "+ 1" to make room for the terminating NUL for the C API
std::string str(length + 1);

// Call the C API passing &str[0] to safely write to the string buffer
...

// Resize back to length
str.resize(length);

(FWIW, я попробовал подход «перезаписи NUL» на MSVC10, и он отлично работает.)

11

Я полагаю, что n3092 больше не актуален, но это то, что у меня есть. Раздел 21.4.5 разрешает доступ к одному элементу. Требуется поз <= размер (). Если поз < size (), тогда вы получите фактический элемент, в противном случае (то есть, если pos == size ()), тогда вы получите неизменяемую ссылку.

Я думаю, что для языка программирования вид доступа, который может изменить значение, считается модификацией, даже если новое значение совпадает со старым значением.

Есть ли в g ++ педантичная библиотека, на которую вы можете ссылаться?

5
По вопросам рекламы [email protected]