Копировать const char *
Я получаю c-строку как параметр из функции, но аргумент, который я получаю, будет уничтожен позже. Поэтому я хочу сделать его копию.
Вот что я имею в виду:
class MyClass
{
private:
const char *filename;
public:
void func (const char *_filename);
}
void MyClass::func (const char *_filename)
{
filename = _filename; //This isn't going to work
}
То, что я хочу достичь, - это не просто присваивать один адрес памяти другому, а копировать содержимое. Я хочу иметь имя файла как "const char *", а не как "char *".
Я попытался использовать strcpy, но для него требуется, чтобы строка назначения не была const.
Есть ли способ? Что-то без использования const_cast по имени файла?
Спасибо.
Ответы
Ответ 1
Используйте std::string
, чтобы скопировать значение, так как вы уже используете С++. Если вам нужен const char*
, используйте c_str()
.
class MyClass
{
private:
std::string filename;
public:
void setFilename(const char *source)
{
filename = std::string(source);
}
const char *getRawFileName() const
{
return filename.c_str();
}
}
Ответ 2
Я согласен с тем, что самое лучшее (по крайней мере, не зная ничего больше о вашей проблеме) - использовать std::string
. Но если вы настаиваете на том, чтобы самостоятельно управлять памятью, вам нужно полностью управлять ею. Итак, способ С++:
class MyClass
{
private:
const char *filename;
MyClass(const MyClass&); // no implementation
MyClass operator=(const MyClass &); // no implementation
public:
MyClass() {filename = 0;}
~MyClass() {delete[] filename;}
void func (const char *_filename);
}
void MyClass::func (const char *_filename)
{
const size_t len = strlen(_filename);
char * tmp_filename = new char[len + 1];
strncpy(tmp_filename, _filename, len);
tmp_filename[len] = '\0'; // I'm paranoid, maybe someone has changed something in _filename :-)
delete[] filename;
filename = tmp_filename;
}
и путь C
class MyClass
{
private:
const char *filename;
MyClass(const MyClass&); // no implementation
MyClass operator=(const MyClass &); // no implementation
public:
MyClass() {filename = 0;}
~MyClass() {free(filename);}
void func (const char *_filename);
}
void MyClass::func (const char *_filename)
{
free(filename);
filename = strdup(_filename); // easier than C++, isn't it?
}
Ответ 3
Вы должны решить, хотите ли вы, чтобы ваше имя файла было const (поэтому его нельзя изменить) или не-const (поэтому его можно изменить в MyClass:: func).
Ответ 4
[Предполагая, что вы продолжаете внедрять внутренние объекты класса C в стиле C, что может или не может быть выгодным с точки зрения скорости разработки и исполнения (в зависимости от всего проекта), но обычно не рекомендуется в пользу из std::string
и друзей.]
Включение
const char *filename;
в
char *filename;
не сделает вас счастливым с strcpy
, так как вам действительно нужна некоторая память для копии вашей строки:)
Для части кода управления ручным управлением памяти см. ответ Tadeusz Kopec, который, похоже, все в порядке.
Кроме того, имейте в виду, что существует разница между
const char *filename; // "filename" points to "const char"
// and is not const itself
char const *filename; // semantically the same as above
и
char * const filename; // "filename" is const and points to "char",
// which is not const
В первом случае вы можете сделать filename
указателем на любую другую строку const char
, во второй, вы можете изменить только эту строку "на месте" (поэтому сохраняя значение filename
тем же, что и он указывает на то же место памяти). Конечно, при необходимости можно объединить эти два (или ни один из них).
P.S. Если вы назовете параметр функции участника _filename
только для того, чтобы избежать столкновения имен с переменной-членом filename
, вы можете просто префикс его с помощью this
(и избавиться от подчеркивания):
void MyClass::func (const char *filename)
{
...
this.filename = copy;
}
Ответ 5
Там есть функция в стандартной библиотеке C (если вы хотите перейти по маршруту C), называемому _strdup. Он использует malloc для фактического распределения, поэтому вам нужно будет позвонить бесплатно, когда закончите со строкой.
Итак, например,
void MyClass::func (const char *_filename)
{
if (filename)
{
free(filename);
}
filename = _strdup(_filename);
}
Конечно, не забудьте освободить имя файла в своем деструкторе.
Ответ 6
Если вы хотите придерживаться простого C, используйте strncpy. Но я согласен с Илья, использую std::string как это уже С++. Если это приложение, которое вызывает ваш метод, вы даже можете получить std::string в первую очередь, поскольку исходный аргумент будет уничтожен.
Ответ 7
Почему у вас это как const, если вам нужно изменить их в одном из методов класса.
В любом случае, нестатические константные члены данных и ссылочные данные не могут присваиваться значениям; вы должны использовать список инициализации с конструктором для их инициализации.
MyClass::MyClass(const char *_filename) : filename( _filename )
{
// filename = _filename; This isn't going to work
}
Инициализатор также может вызывать функцию ниже
MyClass::MyClass(const char *_filename) : filename( getfilename() )
{
// filename = _filename; This isn't going to work
}
Не проверял этот конкретный случай, который является apt, но список инициализации - это способ назначения значений нестационарным элементам данных const.
Ответ 8
char const*
подразумевает, что класс не имеет связанной с ним памяти. Владельцу всегда нужен указатель не const, потому что иначе память не может быть освобождена. Если у вас есть указатель non-const, вы можете выделить для него память, а затем использовать strcpy
(или memcpy
) для копирования самой строки. Однако в вашей ситуации использование std::string
вместо этого является гораздо лучшим вариантом.