Правильность константы в C++ все еще дает мне головные боли. В работе с некоторым старым кодом C я должен для присвоения, превращают строковый объект C++ в струну до и присваивают его переменной. Однако переменная является a char *
и c_str()
возвраты a const char []
. Существует ли хороший способ обойти это, не имея необходимость прокручивать мою собственную функцию, чтобы сделать это?
править: Я также стараюсь не называть новым. Я с удовольствием обменяю немного более сложный код на меньшее количество утечек памяти.
Я думаю, всегда есть strcpy
.
Или используйте строки char *
в частях вашего кода C ++, которые должны взаимодействовать со старым
Или реорганизуйте существующий код, чтобы скомпилировать его с помощью компилятора C ++, а затем использовать std: string
.
Если вы можете позволить себе дополнительное выделение, вместо рекомендуемого 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<char> 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» Мейерса, чтобы получить гораздо более хорошее объяснение, чем я когда-либо мог дать.
Всегда есть const_cast ...
std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Конечно, это в основном подрывает систему типов, но иногда это необходимо при интеграции со старым кодом.
Вы можете использовать метод copy :
len = myStr.copy(cStr, myStr.length());
cStr[len] = '\0';
Где myStr
- ваша строка C ++, а cStr
a char *
с размером не менее myStr.length ()
+1. Кроме того, len
имеет тип size_t
и необходим, потому что копия не завершается нулевым символом cStr
.
Здесь необходимо сделать важное различие: является ли char *
, которому вы хотите присвоить эту «моральную константу»? То есть отбрасывание const
-ness просто формальность, и вы действительно все равно будете рассматривать строку как const
? В этом случае вы можете использовать приведение - в стиле C или C ++ const_cast
. Пока у вас (и у всех, кто когда-либо поддерживает этот код) есть дисциплина рассматривать этот char *
как const char *
, все будет в порядке, но компилятор будет больше не следите за вашей спиной, поэтому, если вы когда-нибудь относитесь к нему как к не const
, вы можете изменять буфер, на который полагается что-то еще в вашем коде.
Если вы знаете, что 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;
Это быстро, легко и правильно.
Неужели это так сложно сделать самому?
#include <string>
#include <cstring>
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 <size_t len>
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;