Законно ли писать в std :: string? - PullRequest
14 голосов
/ 17 апреля 2009

В std :: string есть только члены const для извлечения данных, например c_str (). Однако я могу получить ссылку на первый элемент строки через operator[], и я могу написать в нее.

Например, если у меня есть функция:

void toupper(char *first,char *last_plus_one);

Я могу написать прямо в вектор, получая указатель на первый элемент:

vector<char> message // has "Some Message";
toupper(&message[0],&message[0]+message.size());

Могу ли я сделать то же самое с std :: string?

string message="Some Message";
toupper(&message[0],&message[0]+message.size());

Гарантирует ли стандарт, что расположение памяти действительно линейно? то есть:

&(*(message.begin()+n)) == &message[n]

Спасибо.

Ответы [ 5 ]

22 голосов
/ 17 апреля 2009

Херб Саттер имеет это сказать (http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/#comment-483):

текущий ISO C ++ требует, чтобы & str [0] выкашлял указатель на непрерывные строковые данные (но не обязательно завершенные нулем!), Так что у реализаторов не было особой возможности иметь несмежные строки в любом случае. Для C ++ 0x мы уже приняли гарантию того, что содержимое std :: string действительно должно храниться непрерывно. Для получения подробной информации см. http://www.open -std.org / jtc1 / sc22 / wg21 / docs / lwg-дефектs.html # 530

И Мэтт Остерн говорит, что подобное в документе, на который есть ссылка (http://www.open -std.org / jtc1 / sc22 / wg21 / docs / lwg-дефекты.

Итак, кажется, что вы можете предположить, что после вызова str [0] вы получите изменяемый массив символов (но учтите, что он не обязательно должен заканчиваться нулем).

17 голосов
/ 17 апреля 2009

std :: string потребуется для непрерывного хранения с новым стандартом c ++ 0x. В настоящее время это неопределенное поведение.

5 голосов
/ 17 апреля 2009

Да, вы можете изменить строку.

Вы также можете использовать его в алгоритмах, использующих итераторы.

Вы не можете использовать его так же, как вектор <>, потому что нет гарантии, что элементы находятся в смежных местах памяти (пока: скоро появится ближайший стандарт).

Так что, если вы измените свой подход, чтобы использовать итераторы, а не указатели, он должен работать. И поскольку итераторы ведут себя очень похоже на указатели, изменения кода должны быть незначительными.

template<typename I>
void toupper(I first,I last_plus_one)
{
    // Probably the same code as you had before.
}


{
     std::string  s("A long string With Camel Case");

     toupper(s.begin(),s.end());
}
3 голосов
/ 17 апреля 2009

Как уже указывалось, можно использовать строки в алгоритмах, использующих итераторы; тот же случай может быть реализован с использованием std::transform Пример: - считать строку 's' преобразованной в нижний регистр:

int (*pf)(int)=tolower; //lowercase
std::transform(s.begin(), s.end(), s.begin(), pf); 

С уважением,

0 голосов
/ 17 апреля 2009

Я думаю, что это дает вам неопределенное поведение. Используйте строковый поток для записи, а затем используйте член str () для получения строки потока.

...