开发者

const char* in my class has junk character(s) after it's returned from function

开发者 https://www.devze.com 2023-01-29 02:19 出处:网络
Class: class myclass { public: myclass(void); const char* server; private: char pidchar[6]; int pidnum; }; The 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()

0

精彩评论

暂无评论...
验证码 换一张
取 消