Подтвердить что ты не робот

Копировать 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 по имени файла?

Спасибо.

4b9b3361

Ответ 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 вместо этого является гораздо лучшим вариантом.