2010-12-02 29 views
1

類返回後:爲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; 


} 

從main函數調用它

int _tmain(int argc, TCHAR* argv[]) 
{ 

myclass options; 
options = parseINI("myapp.ini"); 
std::cout << options.server << "\n"; // It prints junk here 
return 0; 
} 

我做錯了什麼?

回答

5

通過GetValue()返回的const char*可能屬於ini對象。當您退出parseIni()功能時,ini超出範圍並被銷燬,這可能意味着您的指針不再有效。

嘗試使用std::string代替server成員類型,而不是const char*

0

iniOptions位於堆棧上,並在函數返回時自動放置。您應該使用堆分配new()

+0

親愛的上帝,請不要忘記嘗試刪除解構者,但是。 – Squirrelsama 2010-12-02 19:44:01

+1

由於RVO,這應該沒有關係。問題是通過`ini`使用其他堆棧分配的內存。 http://stackoverflow.com/questions/1394229/understanding-return-value-optimization-and-returning-temporaries-c – 2010-12-02 19:44:20

+0

即使沒有RVO,這也不會導致問題(除非類有一個錯誤的拷貝構造函數,這是這次不是這種情況)。在這裏沒有理由不按值返回類對象。 – aschepler 2010-12-02 19:49:47

2

看起來您正在使用的內存是在parseINI範圍內CSimpleIniA超出範圍時釋放的。

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; 
1
const char* server = ini.GetValue("", "server", ""); 

該值下降超出範圍時,函數結束,所以當你該指針的值賦給你的對象的服務器的指針,在內存它們指向的地方是有其內存釋放出棧函數的結尾,然後被其他事物超越。

使用std :: string或者甚至只是一個char []將首選修正問題的最少量的更改,因爲它們將通過分配實際值而不是指針等內存中的位置。

儘管如此,你真正應該做的是查找參照透明度。這將防止類似這樣的問題再次發生

1

我推測char*指向char*指向的數據的生命週期與CSimpleIni對象本身相同。因此當ini被銷燬時,從GetValue()返回的指針變爲無效。 (我從來沒有使用過CSimpleIni,並且沒有仔細查看文檔以確定知道,但這就是行爲所指向的)。

我建議改變myclass::server是一個std:string對象,並使用類似設置:

iniOptions.server = std::string(server); 

這將給myclass::server對象是字符串數據的自己的副本。

0

問題是本地變量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非const,你必須把它初始化爲NULL在構造函數和析構函數刪除它。

處理這種情況的更好方法是使用std::string代替char *代替muclass::server。這種方式std::string會照顧你的內存管理,並且代碼將是異常安全的。

如果您muclass::serverstd::string,那麼你根本就

const char* server = ini.GetValue("", "server", ""); 
iniOptions.server = std::string(server); 

而且你不必在構造函數或析構函數用它做任何事情。

1

您在C++中使用類作爲函數返回數據類型的方式是完全錯誤的。 在C++中有兩種數據類型:值類型,引用類型。 類屬於第二類;從一個函數中,你可以返回一個值類型的數據或任何數據的指針。但是你不能重新引用一個引用類型的實體。因爲引用類型的實體將在代碼超出實體定義的範圍之後立即釋放。

您可以在任何一種方式做到:

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: 你做了什麼,而是增加一個asignment方法(運算符=)來MYCLASS