У меня есть функция в библиотеке, которая принимает char*
и изменяет данные.
Я попытался дать ему c_str()
, но С++ docs говорят, что он возвращает const char*
.
Что я могу сделать, кроме как создать массив char и скопировать его в это?
У меня есть функция в библиотеке, которая принимает char*
и изменяет данные.
Я попытался дать ему c_str()
, но С++ docs говорят, что он возвращает const char*
.
Что я могу сделать, кроме как создать массив char и скопировать его в это?
Ничего.
Поскольку std::string
управляет собой своим содержимым, вы не можете иметь доступ на запись к строковым данным. Это поведение undefined.
Однако создание и копирование массива char не сложно:
std::string original("text");
std::vector<char> char_array(original.begin(), original.end());
char_array.push_back(0);
some_function(&char_array[0]);
Вы можете использовать &str[0]
или &*str.begin()
, если:
resize()
;str.size()
в качестве аргумента для размера буфера);\0
, иначе str.size()
вернет "предварительно выделенный размер" вместо "логического" размера строки. Примечание: это гарантировано работает на С++ 11 (где строки гарантированно будут смежными), но не в предыдущих версиях стандарта; тем не менее, реализация стандартной библиотеки, которую я знаю, никогда не выполняла std::basic_string
с несмежным хранилищем.
Тем не менее, если вы хотите пойти в безопасное место, используйте std::vector<char>
(гарантированный соприкосновение с С++ 03); инициализируйте все, что захотите (вы можете скопировать свои данные из строки, используя конструктор, который принимает два итератора, добавив в конце нулевой символ), измените его размер так же, как вы бы сделали с std::string
, и скопируйте его обратно в строку, останавливающуюся на первый символ \0
.
Если вы знаете, что функция не будет изменяться за пределами str.size()
, вы можете получить указатель одним из следующих способов:
void f( char* p, size_t s ); // update s characters in p
int main() {
std::string s=...;
f( &s[0], s.size() );
f( &s.front(), s.size() );
}
Обратите внимание, что это гарантировано в С++ 11, но не в предыдущих версиях стандарта, где он допускал реализацию канатов (т.е. несмежную память)
Если ваша реализация не будет пытаться увеличить длину строки, то:
С++ 11:
std::string data = "This is my string.";
func(&*data.begin());
С++ 03:
std::string data = "This is my string.";
std::vector<char> arr(data.begin(), data.end());
func(&arr[0]);
Здесь класс, который будет генерировать временный буфер и автоматически скопировать его в строку при ее уничтожении.
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
И вот как вы его используете:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Если вы думаете, что видели этот код раньше, это потому, что я скопировал его из вопроса, который я написал: Гарантированное время жизни временного в С++?