2014-12-02 61 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指向一个已经被销毁的对象。

第二段代码不必工作。你有和第一个一样的问题。它的工作原理是未定义行为的结果。