Как, имея std::string, вызвать конструктор, принимающий char*?

Имеется конструктор:

// Конструктор
Marshrut4D (char * val1) 
                      : vecBasePoints(),
                        vecPoints4D(),
                        currentPos(BasePoints4D(EMPTY_DEF,EMPTY_DEF,EMPTY_DEF,EMPTY_DEF,EMPTY_DEF,0,'\0',12))   
{   
    nameType[0] = '\0'; 
    if (val1 != nullptr)
        strcpy(name,val1);
    else
        name[0] = '\0'; 
}

На вход просит, как видно, char*. Но есть одна переменная которая имеет не тип char[32] (большая часть имён в проекте имеет тип char[32], но есть несколько std::string), а std::string. Как поступить в таком случае? Возможно ли как-то вызвать этот конструктор ? (с помощью преобразований std::string).

Попробовал использовать c_str(). Столкнулся теперь с такой проблемой: метод getName возвращает std::string. Результат работы первых двух стейтментов такой какой нужно, в конечном итоге sd1 указывает на нужную строку, но если заменить первые два стейтмента на третий, то в sdd у меня "\0". Имена переменных сделал от балды, пожалуйста, не обращайте на это внимание. Всё это тесты для того, что бы понять что и как работает.

void ContMarshrut4D::addNewMarshrut(PlanFor4D * uplan)
{
    std::string sdfs = uplan->getName();
    const char* sd1 = sdfs.c_str(); //sd1 нужная строка

    const char* sdd = (uplan->getName()).c_str(); //а тут в sdd "\0"
}

Собственно, подытожу вопрос: почему при выполнении const char* sdd = (uplan->getName()).c_str(); результат != результату

    std::string sdfs = uplan->getName();
    const char* sd1 = sdfs.c_str(); //sd1 нужная строка

//-----------тут метод getName---------

class PlanFor4D
{
public:
PlanFor4D() :   traek_(),               
                track_(),               
                name_("\0"),            
                nameType_("\0")         
{

}

~PlanFor4D() {}

void createPlanFromKST(P4_POLETA_NBT * p4_poleta_nbt, char * name);     
std::string getName() { return name_; }
std::string getNameType() { return nameType_; }
PlanFor4D * getPlan() { PlanFor4D * ptr = this; return ptr; }

private:
    
std::vector<BasePoints4D>   traek_; 
std::vector<BasePoints4D>   track_;     
std::string                 name_;          //  Номер борта ВС
std::string                 nameType_;      //  Тип ВС


friend void Marshrut4D::setBasePoints(PlanFor4D * uplan);
};

Ответы (1 шт):

Автор решения: KoVadim

Ваша функция std::string getName() { return name_; } возвращает копию строки. И после точки с запятой в строке

const char* sdd = (uplan->getName()).c_str();

это временный объект уничтожается. И sdd начинает указывать куда то в дебри памяти. Обращение по такому удаленному указателю - UB и оно может приводить к чему угодно (хотя иногда оно даже и работает:) - это законно при UB. Но чаще всего падает в разных, иногда странных, местах).

Когда Вы используете вот так

std::string sdfs = uplan->getName();
const char* sd1 = sdfs.c_str(); //sd1 нужная строка

то копия строки сохраняется в sdfs и живет до конца блока видимости (он же scope). Обычно это до парной закрывающей фигурной скобки. И в этом случае sd1 указывает на рабочую память внутри sdfs.

Что такого в c_str? это функция, которая должна возвращать указатель на си строку. У нее есть по факту два варианта - просто возвратить указатель на внутренний буфер, который будет очищен в деструкторе (обычно так и делается), или создать новый буфер и вернуть указатель на него. Но тогда кто будет очищать память? И такой метод не используется в с++, хотя достаточно часто встречается в разных движках от игр (может называться GetCopyOfBuffer - где то такое видел)

Как пофиксить Ваш код максимально просто? Возвращайте не копию строки, а ссылку на константу.

const std::string& getName() const { return name_; }

и теперь все Ваши варианты будут работать - ведь c_str теперь будет возвращать буфер, который хранит name_. Правда, когда родительский класс PlanFor4D будет уничтожен, то и указатель испортиться. Но скорее всего у Вас этого пока не случится. Ещё один плюс этого метода - не создаются лишние копии.

→ Ссылка