Изменение базового массива char строкового объекта c ++ - PullRequest
10 голосов
/ 20 апреля 2011

Мой код такой:

string s = "abc";
char* pc = const_cast<char*>( s.c_str() );
pc[ 1 ] = 'x';
cout << s << endl;

Когда я скомпилировал приведенный выше фрагмент с использованием GCC, я получил результат "axc" , как и ожидалось. Мой вопрос заключается в том, является ли это безопасным и портативным для изменения базового char массива строки C ++ таким образом? Или могут быть альтернативные подходы для непосредственного управления строковыми данными?

К вашему сведению, я намерен написать некоторые чистые функции C, которые могут вызываться как C, так и C ++, поэтому они могут принимать только char* в качестве аргументов. От char* до строки, я знаю, что это связано с копированием, штраф невыгоден. Так, кто-нибудь может дать некоторые предложения, чтобы справиться с такой ситуацией.

Ответы [ 7 ]

5 голосов
/ 20 апреля 2011

В первой части c_str() возвращает const char*, и это означает, что он говорит.Все, что const_cast достигает в этом случае, - это то, что ваше неопределенное поведение компилируется.

Во второй части, в C ++ 0x std::string гарантированно имеет непрерывное хранилище, как и std::vector в C ++03.Поэтому вы можете использовать &s[0], чтобы получить char* для передачи вашим функциям, если строка не пуста.На практике у всех string реализаций, которые в настоящее время находятся в активной разработке, уже есть непрерывное хранилище: на стандартном заседании комитета был проведен соломенный опрос, и никто не предложил контрпример.Таким образом, вы можете использовать эту функцию сейчас, если хотите.

Однако , std::string использует принципиально иной формат строки, чем строки в стиле C, а именно data + length, а не nul-terminated,Если вы измените строковые данные из ваших функций C, вы не сможете изменить длину строки и не сможете быть уверены, что в конце есть нулевой байт без c_str()std::string может содержать встроенные nuls, которые являются частью данных, поэтому, даже если вы нашли nul, не зная длины, вы все равно не знаете, что нашли конец строки.Вы очень ограничены в том, что вы можете делать в функциях, которые будут корректно работать с обоими видами данных.

5 голосов
/ 20 апреля 2011

(а) Это не обязательно основная строка.std::string::c_str() должна быть копией базовой строки (хотя ошибка в Стандарте C ++ означает, что на самом деле это часто не ... Я считаю, что это исправлено в C ++ 0x).

(б) const_cast удаление константности только взламывает тип переменной: фактический объект по-прежнему const, и вы модифицируете его как Неопределенное поведение - очень плохо.

Проще говоря, не сделайте это.


Можно ли вообще использовать &myString[0]?Он имеет неконстантную версию;опять же, заявлено, что оно совпадает с data()[0], у которого нет неконстантной версии.Кто-то, у кого есть приличная ссылка на библиотеку, может это прояснить.

3 голосов
/ 20 апреля 2011

Как говорили другие, он не переносимый.Но есть и другие опасности.Некоторые реализации std :: string (я знаю, что это делает GCC) используют COW (копирование при записи).

#include <iostream>
#include <string>

int main()
{

    std::string x("abc");
    std::string y;
    y = x; // x and y share the same buffer

    std::cout << (void*)&x[0] << '\n';
    std::cout << (void*)&y[0] << '\n';

    x[0] = 'A'; // COW triggered

    // x and y no longer share the same buffer
    std::cout << (void*)&x[0] << '\n';
    std::cout << (void*)&y[0] << '\n';

    return 0;
}
2 голосов
/ 20 апреля 2011

Очевидный ответ - нет, это неопределенное поведение.С другой стороны, если вы сделаете:

char* pc = &s[0];

, вы сможете получить доступ к базовым данным на практике сегодня и гарантировано в C ++ 11.

1 голос
/ 20 апреля 2011

Это будет зависеть от вашей операционной системы.В библиотеке GNU libc std::string реализован с использованием шаблона copy-on-write (CoW) .Таким образом, если несколько std::string объектов изначально содержат одинаковое содержимое, они все внутренне будут указывать на одни и те же данные.Таким образом, если вы измените любой из них в методе, который вы показываете в своем вопросе, содержимое всех (казалось бы) не связанных std::string объектов изменится.используйте CoW, я не уверен, что там произойдет.

Во всяком случае, это неопределенное поведение, так что я бы остерегался этогоСкорее всего, даже если вы все заработаете, вы в конечном итоге начнете сталкиваться с очень трудными для отслеживания ошибками.

1 голос
/ 20 апреля 2011

Это зависит от неопределенного поведения и поэтому не переносимо.

0 голосов
/ 20 апреля 2011

Вы не должны связываться с базовой строкой. В конце концов, строка - это объект, не могли бы вы связываться с другими объектами таким образом?

Профилировали ли вы свой код, чтобы увидеть, есть ли штраф.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...