Intereting Posts
Как очистить буфер streamstring? Влияние производительности -fno-strict-aliasing Почему компилятор не предупреждает «возвращать адрес локальной переменной или временный» при возврате локальной ссылки на локальную переменную? Преобразование Mat в Keypoint? Понимание того, как тип закрытия Lambda удалил конструктор по умолчанию Запрос содержимого std :: ostringstream Меню отображается только после перехода на приложение / рабочий стол на MacOS с использованием Qt5 Как мне получить IIS для загрузки родной DLL, на которую ссылается моя служба WCF? Использование сокетов SSL и не-SSL-сокетов одновременно в Boost.Asio? Удаление объекта с защищенным деструктором Создайте сокет в коде Android (не в приложении для Android), получив разрешение Отказано Динамическое распределение двумерных массивов в C Почему имеет смысл дать определение чистой виртуальной функции? c ++ проблема с перегрузкой функции Разбор пары ints с повышающим духом

Могу ли я получить строку non-const C из строки C ++?

Const-correctness в C ++ все еще дает мне головные боли. При работе с каким-то старым C-кодом мне нужно назначить поворот строкового объекта C ++ в строку C и присвоить его переменной. Однако переменная char * и c_str() возвращает const char [] . Есть ли хороший способ обойти это без необходимости выполнять мою собственную функцию?

edit: Я также пытаюсь избежать вызова нового. Я с радостью обменю немного более сложный код на меньшее количество утечек памяти.

Я думаю, что всегда есть strcpy .

Или используйте char* строки в частях вашего кода на C ++, которые должны взаимодействовать со старыми вещами.

Или реорганизовать существующий код для компиляции с компилятором C ++, а затем использовать std:string .

Поскольку для меня необъяснимые причины никто не отвечал так, как я сейчас это делаю, и поскольку другие вопросы сейчас закрываются, указывая на это, я добавлю это здесь, хотя приход на год слишком поздно будет означать, что он висит на самом дно кучи …


С C ++ 03 std::string не гарантирует сохранение своих символов в непрерывной части памяти, а результат c_str() не должен указывать на внутренний буфер строки, поэтому единственный способ гарантировать работа такова:

 std::vector buffer(s.begin(), s.end()); foo(&buffer[0], buffer.size()); s.assign(buffer.begin(), buffer.end()); 

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

 foo(&s[0], s.size()); 

Однако это требует осторожности: результат &s[0] (как результат s.c_str() , BTW) гарантируется только до тех пор, пока не будет вызвана какая-либо функция-член, которая может изменить строку. Поэтому вы не должны хранить результат этих операций в любом месте. Как и в моих примерах, самое безопасное должно быть сделано с ними в конце полного выражения.

Здесь необходимо сделать важное различие: есть ли char* который вы хотите присвоить этому «морально постоянному»? То есть, изгоняющая бессознательность просто техническая, и вы действительно будете обрабатывать эту строку как const ? В этом случае вы можете использовать const_cast – C-стиль или C ++-стиль const_cast . Пока вы (и кто-либо еще, кто когда-либо поддерживает этот код), имеют дисциплину, чтобы рассматривать этот char* как const char* , вы будете в порядке, но компилятор больше не будет следить за вашей спиной, поэтому, если вы когда-нибудь будете лечить он как const вы можете модифицировать буфер, на который опирается что-то еще в вашем коде.

Если ваш char* будет рассматриваться как не const , и вы намереваетесь изменить то, на что он указывает, вы должны скопировать возвращенную строку, а не отбросить ее const -ness.

Всегда есть const_cast …

 std::string s("hello world"); char *p = const_cast(s.c_str()); 

Конечно, это в основном подрывает систему типов, но иногда это необходимо при интеграции со старым кодом.

Вы можете использовать метод копирования :

 len = myStr.copy(cStr, myStr.length()); cStr[len] = '\0'; 

Где myStr – ваша строка C ++, а cStrchar * с myStr.length() не менее myStr.length() +1. Кроме того, len имеет тип size_t и необходим, поскольку копия не завершает нуль cStr .

Если вы можете позволить себе дополнительное выделение, вместо рекомендуемого strcpy я бы рассмотрел использование std::vector следующим образом:

 // suppose you have your string: std::string some_string("hello world"); // you can make a vector from it like this: std::vector some_buffer(some_string.begin(), some_string.end()); // suppose your C function is declared like this: // some_c_function(char *buffer); // you can just pass this vector to it like this: some_c_function(&some_buffer[0]); // if that function wants a buffer size as well, // just give it some_buffer.size() 

Для меня это немного больше, чем для C ++, чем для strcpy . Взгляните на «Эффективный STL-элемент» Мейерса 16, чтобы получить более приятное объяснение, чем я мог когда-либо предоставить.

Если вы знаете, что std::string не изменится, будет выполняться приведение в стиле C.

 std::string s("hello"); char *p = (char *)s.c_str(); 

Конечно, p указывает на некоторый буфер, управляемый std::string . Если std::string выходит из области видимости или изменяется буфер (т.е. записывается в), p , вероятно, будет недействительным.

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

Если c_str() возвращает вам копию внутреннего буфера строкового объекта, вы можете просто использовать const_cast<> .

Однако, если c_str() предоставляет вам прямой доступ к внутреннему буферизующему объекту строкового объекта, сделайте явную копию вместо удаления константы.

Поскольку c_str () дает вам прямой доступ к структуре данных, вы, вероятно, не должны ее использовать. Самый простой способ сделать это, не перераспределяя буфер, – это просто использовать strdup.

 char* tmpptr; tmpptr = strdup(myStringVar.c_str(); oldfunction(tmpptr); free tmpptr; 

Это быстро, легко и правильно.

 std::string vString; vString.resize(256); // allocate some space, up to you char* vStringPtr(&vString.front()); // assign the value to the string (by using a function that copies the value). // don't exceed vString.size() here! // now make sure you erase the extra capacity after the first encountered \0. vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end()); // and here you have the C++ string with the proper value and bounds. 

Так вы превращаете строку C ++ в строку C. Но убедитесь, что вы знаете, что делаете, так как очень легко выйти за границы, используя функции raw string. Бывают моменты, когда это необходимо.

Просто используйте const_cast(str.data())

Не чувствуйте себя плохо или странно об этом, это отличный стиль для этого.

Он гарантированно работает на C ++ 11. Тот факт, что он является const квалифицированным вообще, является, возможно, ошибкой по оригинальному стандарту перед этим; в C ++ 03 было возможно реализовать string в виде прерывистого списка памяти, но никто этого не делал. На земле нет компилятора, который реализует string как нечто, отличное от непрерывного блока памяти, поэтому не стесняйтесь относиться к ней как таковой с полной уверенностью.

Неужели это трудно сделать самому?

 #include  #include  char *convert(std::string str) { size_t len = str.length(); char *buf = new char[len + 1]; memcpy(buf, str.data(), len); buf[len] = '\0'; return buf; } char *convert(std::string str, char *buf, size_t len) { memcpy(buf, str.data(), len - 1); buf[len - 1] = '\0'; return buf; } // A crazy template solution to avoid passing in the array length // but loses the ability to pass in a dynamically allocated buffer template  char *convert(std::string str, char (&buf)[len]) { memcpy(buf, str.data(), len - 1); buf[len - 1] = '\0'; return buf; } 

Использование:

 std::string str = "Hello"; // Use buffer we've allocated char buf[10]; convert(str, buf); // Use buffer allocated for us char *buf = convert(str); delete [] buf; // Use dynamic buffer of known length buf = new char[10]; convert(str, buf, 10); delete [] buf;