我有这个非常简单的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更改为另一个数字,也会记录完全相同的内容。
答案 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
指向一个已被破坏的对象。
第二段代码无需工作。你有与第一个问题相同的问题。它起作用的事实是未定义行为的影响。