В 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
персонажи. Это собирается переписать нулевой терминатор.
По общему признанию, это собирается переписать нулевой терминатор с нулевым символом. Хорошие шансы, что это будет работать (действительно, я не могу себе представить, как это не может Работа).
Но мне все равно, что «работает». Я хочу знать, согласно спецификации, можно ли перезаписывать нулевой терминатор нулевым символом?
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 разрешает доступ к одному элементу. Требуется поз <= размер (). Если поз < size (), тогда вы получите фактический элемент, в противном случае (то есть, если pos == size ()), тогда вы получите неизменяемую ссылку.
Я думаю, что для языка программирования вид доступа, который может изменить значение, считается модификацией, даже если новое значение совпадает со старым значением.
Есть ли в g ++ педантичная библиотека, на которую вы можете ссылаться?