Законно ли перезаписывать нулевой терминатор 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 персонажи. Это собирается переписать нулевой терминатор.

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

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

4 ответа

Решение

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

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

К сожалению, это 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()],

Согласно спецификации, перезаписывая завершающий 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, и он отлично работает.)

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

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

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

Другие вопросы по тегам