const char* in my class has junk character(s) after it's returned from function
Class:
class myclass {
public:
myclass(void);
const char* server;
private:
char pidchar[6];
int pidnum;
};
The function
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;
}
Calling it from the main function
int _tmain(int argc, TCHAR* argv[])
{
myclass options;
options = pars开发者_Go百科eINI("myapp.ini");
std::cout << options.server << "\n"; // It prints junk here
return 0;
}
What did I do wrong?
The const char*
returned by GetValue()
probably belonged to the ini
object. When you exited the parseIni()
function, ini
went out of scope and was destroyed, which could mean your pointer is no longer valid.
Try using a std::string
for the server
member type instead of const char*
.
It looks like you are using memory that is released when CSimpleIniA
goes out of scope in parseINI
.
const char* server = ini.GetValue("", "server", "");
iniOptions.server = server;
Copy the value that is returned into a new memory block before you return from the parseINI
function.
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;
const char* server = ini.GetValue("", "server", "");
This value is falling out of scope when the function terminates, so when you assign the value of that pointer to your object's server pointer, the place in memory they point to is having its memory freed off the stack at the end of the function, and it's then overtaken by other things.
Using a std::string or even just a char[] will be preferred to just fix the problem with the least amount of changes, as they will by assigned the actual value and not a location in memory like pointers.
What you really should do is look up referential transparency, though. That will prevent problems like this from occurring ever again
I's guess that the lifetime of the data pointed to by the char*
returned from CSimpleIniA::GetValue()
is the same as the CSimpleIni
object itself. So when ini
is destructed, the pointer returned from GetValue()
becomes invalid. (I've never used CSimpleIni, and haven't looked at the docs carefully enough to know for sure, but that's what the behavior points to).
I'd suggest changing myclass::server
to be a std:string
object and set it using something like:
iniOptions.server = std::string(server);
which will give the myclass::server
object it's own copy of the string data.
The way you are using class as a function returned data type in C++ is totally wrong. In C++ there are 2 kinds of data type: value type, reference type. class belongs to second one; From a function you can return a value type data or a pointer of any data.But you cann't retun a entity of a reference type. Because a entity of a reference type will be released right after the code reached out of the scope which the entity is defined.
You can do in either way:
1: define parseINI as:
myclass* parseINI(const char* file)
{
myclass* iniOptions = new myclass();
........
return iniOptions;
}
and then use it like this:
myclass* options = parseINI("myapp.ini");
2: define parseINI as:
void parseINI(myclass& options, const char* file)
{
........//asigne value to options's members
}
and then use it like this:
myclass options;
parseINI(options,"myapp.ini");
3: Do what you did, but add a asignment method (operator=) to myclass
The problem is that the local variable server
points to a character buffer returned by ini.GetValue()
, which is destroyed when paraseINI()
returns.
One way to fix this is to allocate a new buffer yourself and copy the characters.
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
For this to work you have to make myclass::server
non-const, and you have to initialize it to NULL in the constructor and delete it in the destructor.
A better way to deal with this situation would be use std::string
instead of char *
for muclass::server
. This way std::string
would take care of memory management for you, and the code would be exception-safe.
If you make muclass::server
an std::string
, then you simply do
const char* server = ini.GetValue("", "server", "");
iniOptions.server = std::string(server);
And you do not have to do anything with it in the constructor or the destructor.
iniOptions is located on the stack and disposed automatically when the function returns. You should allocate it on heap using new()
精彩评论