Скопировать const char * - PullRequest
       53

Скопировать const char *

12 голосов
/ 18 февраля 2010

Я получаю 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_cast для имени файла?

Спасибо.

Ответы [ 8 ]

25 голосов
/ 18 февраля 2010

Используйте std::string для копирования значения, поскольку вы уже используете C ++. Если вам нужно 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();
    }
}
7 голосов
/ 18 февраля 2010

Я согласен, что лучше всего (по крайней мере, ничего не зная о вашей проблеме) использовать std::string. Но если вы настаиваете на управлении памятью самостоятельно, вы должны полностью ею управлять. Итак, C ++ способ:

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 way

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?
}
2 голосов
/ 18 февраля 2010

Вы должны решить, хотите ли вы, чтобы ваше имя файла было константным (чтобы его нельзя было изменить) или неконстантным (чтобы его можно было изменить в MyClass :: func).

1 голос
/ 18 февраля 2010

В стандартной библиотеке C есть функция (если вы хотите пройти по маршруту C), которая называется _strdup. Он использует malloc для фактического размещения, поэтому вам нужно будет вызывать free, когда закончите со строкой.

Так, например,

void MyClass::func (const char *_filename)
{
    if (filename)
    {
        free(filename);
    }
    filename = _strdup(_filename);
}

Конечно, не забудьте освободить имя файла в вашем деструкторе.

1 голос
/ 18 февраля 2010

[Предполагая, что вы продолжаете реализовывать внутренние компоненты вашего класса в стиле C, что может или не может быть полезным с точки зрения скорости разработки и выполнения (в зависимости от дизайна всего проекта), но обычно не рекомендуется в пользу из std::string и друзей.]

Поворот

const char *filename;

в

char *filename;

не порадует вас strcpy, так как вам на самом деле нужно немного памяти для копирования вашей строки:)

Информацию о ручном коде управления памятью см. В ответе Тадеуша Копека, с которым все в порядке.

Кроме того, имейте в виду, что есть разница между

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;
}
0 голосов
/ 18 февраля 2010

Почему у вас это как const, если вам нужно изменить их в одном из методов класса.

В любом случае, нестатическим элементам данных 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 
}

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

0 голосов
/ 18 февраля 2010

Если вы хотите придерживаться простого C, используйте strncpy.Но я согласен с Ильей, используйте std :: string, так как это уже C ++.Если ваше приложение вызывает ваш метод, вы можете даже получить std :: string на первом месте, так как исходный аргумент будет уничтожен.

0 голосов
/ 18 февраля 2010

char const* означает, что классу не принадлежит связанная с ним память.Владельцу всегда нужен неконстантный указатель, потому что иначе память не может быть освобождена.Если у вас есть неконстантный указатель, вы можете выделить для него память, а затем использовать strcpy (или memcpy) для копирования самой строки.Однако в вашей ситуации использование std::string вместо этого является гораздо лучшим вариантом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...