2015-05-12 9 views
3

Я сражаюсь со старым c-style-интерфейсом. У меня есть функция с такой подписью:Можно ли использовать оператор [] для std :: string

/// if return_value == NULL only the length is returned 
void f(char * return_value, size_t * size_only_known_at_runtime); 

Вопрос мой, есть ли следующий код в безопасности?

std::size required; 
f(NULL, &required); 
std::string s; 
s.resize(required); 
f(&s[0], &required); 

Есть ли лучший способ получить данные в строку?

+2

Что случилось с этим? Это довольно распространенный шаблон при взаимодействии с C API. –

+3

Почему бы не использовать 's.c_str()'? – Petr

+0

см. Http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/#comment-483 –

ответ

7

Да, это безопасно, по крайней мере, из C++ 11. Из [string.require], курсив:

полукокса подобные объекты в basic_string объекте должны храниться смежно. То есть для любого элемента basic_string идентификатор &*(s.begin() + n) == &*s.begin() + n должен содержать все значения n, такие как 0 <= n < s.size().

Это было разрешение DR 530. До C++ 11 это не было явным в стандарте, хотя это было сделано на практике в любом случае.

В C++ 14, это требование было перемещено в положении [basic.string]:

basic_string представляет собой непрерывный контейнер (23.2.1).

где [container.requirements.general]:

непрерывный контейнер представляет собой контейнер, который поддерживает случайные итераторы доступа (24.2.7) и чей член типа iterator и const_iterator являются смежными итераторы (24.2.1).

где [iterator.requirements.general]:

итераторов, что дополнительно удовлетворяет требование, что, для целочисленных значений n и разыменовываемого итератора ценит a и (a + n), *(a + n) эквивалентно *(addressof(*a) + n), называется Прилегающие итераторы.

+0

Есть ли также гарантия о том, что оно завершено нулем или нет? – MicroVirus

+2

@MicroVirus №. Неравенство есть ' Barry

+0

Заметим, что, поскольку мы говорим о C++ 11, теперь для этого есть удобная функция-член, [ 's.data()'] (http://en.cppreference.com/w/cpp/string/basic_string/data), который, возможно, более читабельен, чем старый добрый '& s [0]'. – ComicSansMS

1

вопрос, является ли код

std::size_t required_size; 
f(nullptr, &required_size); 
std::string s; 
s.resize(required_size); 
f(&s[0], &required_size); 

безопасен.

Это зависит от того, C++ стандарт один предполагает, но так как это Неопределенное поведение для случая required_size = 0 в C++ 03 и C++ 98, общий ответ нет, это не безопасно в целом.


В C++ 03 std::string формально не гарантирован иметь непрерывный буфер, но на практике все сохранившиеся реализации имели непрерывный буфер.Во всяком случае, теперь после C++ 11, где в стандарте была включена стандартная встроенная поддержка буфера, не будет никаких новых реализаций C++ 03 с несмежным буфером. Следовательно, это не проблема.

Проблема скорее в том, что 03 std::basic_string::operator[] C++ была определена следующим образом:

C++ 03 §21.3.4/1:

Возвращает: Если pos < size() , возвращает data()[pos]. В противном случае, если pos == size(), версия const возвращает charT(). В противном случае поведение не определено.

Таким образом, для не- const строки s размера 0, в C++ 03 это Неопределенное поведение ™ сделать индексацию s[0].

В С ++ 11 соответствующий пункт §21.4.3/2 говорит вместо того, что результат “ *(begin() + pos), если pos < size(), в противном случае это ссылка на объект типа T со значением charT(); ссылочное значение не должно изменяться. ”


Вот код, который работает независимо от того, какой стандарт C++ компилятор использует:

std::size_t required_size; 
f(NULL, &required_size); // Establish required buffer size. 
if(required_size > 0) 
{ 
    std::string s(required_size, '#'); 
    f(&s[0], &required_size); 
    s.resize(strlen(&s[0])); 
} 
Смежные вопросы