Как сохранить const char * в char *?

У меня этот код работает как ожидалось:

#define MAX_PARAM_NAME_LEN 32

const char* GetName()
{
    return "Test text";
}

int main()
{
    char name[MAX_PARAM_NAME_LEN];
    strcpy(name, GetName());    

    cout << "result: " << name << endl;
}

Если я хочу сохранить результат в char * (потому что некоторые функции в рамках Framework, которые я использую, используют только char * в качестве ввода) без использования strcpy (для практичности и удобочитаемости кода, и обучение тоже), как я мог это сделать? Сохранение в const, это хорошо работает:

const char* name;
name = GetName();

но у меня все еще есть const.

Попытка просто использовать char*:

char* name;
name = GetName();

Я получаю invalid conversion from 'const char*' to 'char*'. Какая лучшая привычка для такого рода преобразования?

Ответ 1

return "Test text"; возвращает указатель на литеральный литерал только для чтения.

Если вы используете функцию, которая принимает char* в качестве ввода, и у вас есть const char* (например, литерал строки только для чтения), тогда вы должны предоставить глубокую копию строки, начинающейся при этом const char* к таким функциям.

Кроме того, вы рискуете поведения undefined во время выполнения, если функция пытается изменить строку только для чтения.

То, что у вас сейчас есть, является адекватным; если вы не можете работать с std::string. (Если вы можете работать с std::string, и все ваши функции фреймворка принимают вход const char*, то я предлагаю вам реорганизовать ваш код на использование std::string и передать результат метода c_str() на эту строку класс для ваших функций фреймворка.)

Наконец, если для некоторых ваших фреймворческих функций требуется char*, вы всегда можете создать себе небольшой класс адаптера:

class Adapter
{
public:
    Adapter(const& Adapter) = delete; /*don't try to copy me please*/
    Adapter& operator=(const Adapter& ) = delete; /*don't try to copy me please*/
    Adapter(const char* s) : m_s(::strdup(s))
    {
    }
    ~Adapter() /*free memory on destruction*/
    {
        ::free(m_s); /*use free to release strdup memory*/
    }
    operator char*() /*implicit cast to char* */
    {
        return m_s;
    }
private:
    char* m_s;
};

Тогда для функции void foo(char* c) вы можете вызвать foo(Adapter("Hello"/*or any const char* */)); и foo сделать так, как это нравится, с char*, встроенным в анонимное временное! Вы даже можете улучшить этот класс, чтобы взять конструктор в char*, где в этом случае берется только мелкая копия указателя (и деструктор не удаляет память).

Ответ 2

Лучшей привычкой для такого преобразования является использование std::string во всем коде. Поскольку используемая вами структура принимает const char* как ее вход, вы всегда можете передать ей результаты c_str() на свой std::string:

std::string GetName() {
    return "Test text";
}

int main() {
    std::string name = GetName();
    int res = external_framework_function(name.c_str());
    cout << "result: " << res << " for " << name << endl;
}

Лучше всего использовать const char* в вашем коде:

const char* name = GetName();

Поскольку используемая вами структура принимает const char*, вы тоже хороши здесь.

Если вам нужен указатель, отличный от константы, копирование строки невозможно. Вы можете сделать функцию, которая сделает это за вас, но вы несете ответственность за освобождение копий, которые вы получаете от нее:

char* copy(const char* orig) {
    char *res = new char[strlen(orig)+1];
    strcpy(res, orig);
    return res;
}
...
char *name = copy(GetName());
...
delete[] name;

Ответ 3

В С++ типичным способом "drop const" является использование const_cast<>:

char *name = const_cast<char*>(GetName());

Это, конечно, нахмурило, уродливое и потенциально опасное, так как действительно возможно, что GetName() возвращает указатель на то, что не следует изменять, а затем вы идете и даете себе разрешение на его изменение. Это хороший способ получить очень трудно найти ошибки в этом случае.

Обходным путем является использование std::string в качестве временной области хранения; это будет означать копирование строки, но это может быть приемлемым по производительности:

std::string s(GetName());
char *name = s.c_str();

Это, конечно, будет работать только в том случае, если name не поддерживается, когда s выходит за рамки. Если это так, то у вас будет некоторый вид постоянного уровня хранения строк.

Ответ 4

Вы можете явно его бросить. (char*) getName(). Но вы, вероятно, не должны. Поскольку бит const означает нечто вроде "обещание не менять его". Поэтому, если у меня есть функция void foo(const char* string), я уверен: "Дайте мне указатель на строку, я ее не изменю". И если вы объявляете переменную const char* string = "hello"; Вы говорите, эта строка не должна изменяться. И поскольку вы выполняете это обещание, компилятор знает и может сделать ваш код более эффективным. Вот почему:

const char* a = "hello";
const char* b = "hello";
(a==b); //is probably true

ваш компилятор знает, что вы не измените a или b, чтобы он указывал на тот же адрес, поэтому он должен хранить только одну строку "hello". Если теперь вы собираетесь изменить a, то также будет изменен b, и это не то, что вы хотели.

Короче говоря, если вы абсолютно уверены, что функция вашего вызова не изменит строку, вы можете явно ее бросить. (или лучше, измените функцию на (const char*), если она ваша).
Если вы не уверены, вам придется сделать копию. (Как вы уже делаете с strcpy()).