在成员变量中存储std :: to_string(x).c_str()会产生垃圾

时间:2014-12-02 18:19:08

标签: c++ xcode

我有这个非常简单的C ++程序:

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更改为另一个数字,也会记录完全相同的内容。

3 个答案:

答案 0 :(得分:4)

此时

 _numberString = to_string(number).c_str();

您正在存储指向临时std::string值的实习数据的指针,该指针在该行代码后无效。

访问_numberString会有效地调用未定义的行为。


正如评论中所述,将_numberString 1 成员保留为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_或其他前缀约定(例如我)之类的模式,请使用我的示例中所示的后缀_

答案 1 :(得分:2)

只要字符串在范围内(并且未更改),c_str的返回值仅有效。您的匿名临时文件在声明结尾处超出范围。

考虑将std :: string作为成员变量而不是指针类型,或者存储数值本身。

答案 2 :(得分:1)

c_str()返回指向它所调用的std::string实例的缓冲区的指针。 std::to_string()返回的对象是临时对象,在构造函数体的末尾被销毁。这使得_numberString指向一个已被破坏的对象。

第二段代码无需工作。你有与第一个问题相同的问题。它起作用的事实是未定义行为的影响。