const char* в моем классе имеет ненужные символы после того, как он вернулся из функции
Учебный класс:
class myclass {
public:
myclass(void);
const char* server;
private:
char pidchar[6];
int pidnum;
};
Функция
myclass parseINI(const char* file)
{
myclass iniOptions;
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile(file);
const char* server = ini.GetValue("", "server", "");
iniOptions.server = server;
std::cout << server << "\n"; // Prints the correct value here
fflush(stdout);
return iniOptions;
}
Вызов его из основной функции
int _tmain(int argc, TCHAR* argv[])
{
myclass options;
options = parseINI("myapp.ini");
std::cout << options.server << "\n"; // It prints junk here
return 0;
}
Что я сделал не так?
7 ответов
const char*
вернулся GetValue()
вероятно, принадлежал к ini
объект. Когда вы вышли из parseIni()
функция, ini
вышел из области видимости и был уничтожен, что может означать, что ваш указатель больше не действителен.
Попробуйте использовать std::string
для server
тип элемента вместо const char*
,
Похоже, вы используете память, которая освобождается, когда CSimpleIniA
выходит за рамки в parseINI
,
const char* server = ini.GetValue("", "server", "");
iniOptions.server = server;
Скопируйте значение, которое возвращается в новый блок памяти, прежде чем вернуться из parseINI
функция.
string server = ini.GetValue("", "server", "");
iniOptions.server = new char[server.length() + 1];
std::copy(server.begin(), server.end(), iniOptions.server);
iniOptions.server[server.length()] = 0;
Я предполагаю, что время жизни данных, на которые указывает char*
вернулся из CSimpleIniA::GetValue()
такой же, как CSimpleIni
сам объект Так когда ini
уничтожен, указатель возвращается из GetValue()
становится недействительным. (Я никогда не использовал CSimpleIni и не достаточно внимательно изучал документы, чтобы точно знать, но именно на это указывает поведение).
Я бы предложил изменить myclass::server
быть std:string
Объект и установить его, используя что-то вроде:
iniOptions.server = std::string(server);
который даст myclass::server
возражать это собственная копия строковых данных.
const char* server = ini.GetValue("", "server", "");
Это значение выходит за пределы области действия, когда функция завершается, поэтому, когда вы присваиваете значение этого указателя указателю сервера вашего объекта, место в памяти, на которое они указывают, освобождает память из стека в конце функции, и затем его настигли другие вещи.
Использование std::string или даже просто char[] будет предпочтительным, чтобы просто решить проблему с наименьшим количеством изменений, так как они будут назначены фактическим значением, а не местом в памяти, как указатели.
Что вы действительно должны сделать, так это посмотреть ссылочную прозрачность. Это предотвратит повторение подобных проблем
То, как вы используете класс как функцию, возвращает тип данных в C++, совершенно неверно. В C++ существует 2 типа данных: тип значения, ссылочный тип. класс принадлежит второму; Из функции вы можете вернуть данные типа значения или указатель любых данных. Но вы не можете перенастроить объект ссылочного типа. Потому что объект ссылочного типа будет освобожден сразу после того, как код выйдет из области, в которой определен объект.
Вы можете сделать любым способом:
1: определить parseINI как:
myclass* parseINI(const char* file)
{
myclass* iniOptions = new myclass();
........
return iniOptions;
}
и затем используйте это так:
myclass* options = parseINI("myapp.ini");
2: определить parseINI как:
void parseINI(myclass& options, const char* file)
{
........//asigne value to options's members
}
и затем используйте это так:
myclass options;
parseINI(options,"myapp.ini");
3: Сделайте то, что вы сделали, но добавьте метод присвоения (operator=) в myclass
iniOptions располагается в стеке и удаляется автоматически при возврате функции. Вы должны распределить его по куче, используя new()
Проблема в том, что локальная переменная server
указывает на символьный буфер, возвращаемый ini.GetValue()
, который разрушается при paraseINI()
возвращается.
Один из способов исправить это - выделить новый буфер самостоятельно и скопировать символы.
const char* server = ini.GetValue("", "server", "");
int length = strlen(server) + 1; // length of the string +1 for the NULL character.
delete [] iniOptions.server; // free the old buffer
iniOptions.server = new char[length]; // allocate your own buffer
strncpy(iniOptions.server, server, length); // copy the characters
Чтобы это работало, нужно сделать myclass::server
неконстантный, и вы должны инициализировать его в NULL в конструкторе и удалить его в деструкторе.
Лучшим способом справиться с этой ситуацией будет использование std::string
вместо char *
за muclass::server
, Сюда std::string
позаботится об управлении памятью для вас, и код будет безопасным для исключений.
Если вы делаете muclass::server
std::string
тогда вы просто делаете
const char* server = ini.GetValue("", "server", "");
iniOptions.server = std::string(server);
И вам не нужно ничего с этим делать в конструкторе или деструкторе.