String.c_str() is const?

У меня есть функция в библиотеке, которая принимает char* и изменяет данные.

Я попытался дать ему c_str(), но С++ docs говорят, что он возвращает const char*.

Что я могу сделать, кроме как создать массив char и скопировать его в это?

Ответ 1

Ничего.

Поскольку 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]);

Ответ 2

Вы можете использовать &str[0] или &*str.begin(), если:

  • вы явно выделяете все пространство, необходимое для функции с resize();
  • функция не пытается превышать предопределенный размер буфера (вы должны передать str.size() в качестве аргумента для размера буфера);
  • когда функция возвращает, вы явно обрезаете строку с помощью первого найденного символа \0, иначе str.size() вернет "предварительно выделенный размер" вместо "логического" размера строки.

Примечание: это гарантировано работает на С++ 11 (где строки гарантированно будут смежными), но не в предыдущих версиях стандарта; тем не менее, реализация стандартной библиотеки, которую я знаю, никогда не выполняла std::basic_string с несмежным хранилищем.

Тем не менее, если вы хотите пойти в безопасное место, используйте std::vector<char> (гарантированный соприкосновение с С++ 03); инициализируйте все, что захотите (вы можете скопировать свои данные из строки, используя конструктор, который принимает два итератора, добавив в конце нулевой символ), измените его размер так же, как вы бы сделали с std::string, и скопируйте его обратно в строку, останавливающуюся на первый символ \0.

Ответ 3

Если вы знаете, что функция не будет изменяться за пределами 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, но не в предыдущих версиях стандарта, где он допускал реализацию канатов (т.е. несмежную память)

Ответ 4

Если ваша реализация не будет пытаться увеличить длину строки, то:

С++ 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]);

Ответ 5

Здесь класс, который будет генерировать временный буфер и автоматически скопировать его в строку при ее уничтожении.

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);

Если вы думаете, что видели этот код раньше, это потому, что я скопировал его из вопроса, который я написал: Гарантированное время жизни временного в С++?