2014-12-02 64 views
-1

我有這種很簡單的C++程序:在成員變量存儲的std :: to_string(x)的.c_str()產生垃圾

using namespace std; 

class TheClass 
{ 
private: 
    const char *_numberString; 

public: 
    TheClass(int number) 
    { 
     _numberString = to_string(number).c_str(); 
    } 

    operator const char *() 
    { 
     return _numberString; 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 
    TheClass instance = 123; 
    cout << (const char *)instance << endl; 

    return 0; 
} 

當我在Xcode運行它,它記錄\367\277_\377。如果我改成這樣但是:

using namespace std; 

class TheClass 
{ 
public: // Change 1/2 
    const char *_numberString; 

public: 
    TheClass(int number) 
    { 
     _numberString = to_string(number).c_str(); 
    } 

    operator const char *() 
    { 
     return _numberString; 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 
    TheClass instance = 123; 
    instance._numberString = to_string(123).c_str(); // Change 2/2 
    cout << (const char *)instance << endl; 

    return 0; 
} 

它記錄123像它應該。我看不到我做錯了什麼。即使我將123更改爲另一個號碼,也會記錄完全相同的內容。

+1

絕對沒有理由訴諸'char *'。 iostream的'operator <<'處理'std :: string'就好了。 – PaulMcKenzie 2014-12-02 18:24:53

+0

@Cyber​​我沒有看到Q&A真的是一個騙局。我真的很樂意爲此解決這個問題,但是這個鏈接問題至少錯過了提供一個MCVE,而這個問題。此外,所描述的情況稍有不同,從給出的答案中可以看出實際發生的情況。 – 2014-12-02 19:33:33

回答

3

此時

_numberString = to_string(number).c_str(); 

要存儲的指針到一個臨時std::string值的實習數據,即該行代碼後失效。

訪問_numberString有效地調用未定義的行爲。


正如在評論中提到,有沒有點到_numberString 成員保持爲const char*。使用std::string成員,而不是:

class TheClass { 
private: 
    std::string numberString_; 

public: 
    TheClass(int number) : numberString_(to_string(number)) { 
    } 

    operator const std::string&() { 
     return numberString_; 
    } 
}; 

1),則不應使用前綴_類成員的名字,這是保留給編譯器和標準執行內部函數。如果您不喜歡像m_或其他前綴約定(如我)的模式,只需使用後綴_,如我的示例中所示。

2

c_str的返回值僅在字符串處於作用域(且未更改)時纔有效。在聲明結束時,您的匿名臨時超出範圍。

考慮將std :: string作爲成員變量而不是指針類型,或者存儲數值本身。

1

c_str()返回指向調用的std::string實例的緩衝區的指針。由std::to_string()返回的對象是一個臨時對象,在構造函數體的末尾被銷燬。這就讓_numberString指向一個已經被銷燬的對象。

第二段代碼不必工作。你有和第一個一樣的問題。它的工作原理是未定義行爲的結果。