我还在学习c ++,所以请耐心等待。我正在编写一个关于boost文件系统路径的简单包装器 - 我在返回临时字符串方面遇到了奇怪的问题。这是我的简单类(这不是确切的,但非常接近):
typedef const char* CString;
typedef std::string String;
typedef boost::filesystem::path Path;
class FileReference {
public:
FileReference(const char* path) : mPath(path) {};
// returns a path
String path() const {
return mPath.string();
};
// returns a path a c string
CString c_str() const {
return mPath.string().c_str();
};
private:
Path mPath;
}
使用下面的小测试代码:
FileReference file("c:\\test.txt");
OutputDebugString(file.path().c_str()); // returns correctly c:\test.txt
OutputDebugString(file.c_str()); // returns junk (ie îþîþîþîþîþîþîþîþîþîþî.....)
我很确定这必须处理临时工,但我无法弄清楚为什么会这样 - 不应该一切都正确复制吗?
答案 0 :(得分:8)
CString c_str() const {
return mPath.string().c_str();
};
mPath.string()
会返回std::string
的副本。该副本存储在临时表中,该副本将在此表达式的末尾被销毁。
.c_str()
返回一个指向内存的指针,当字符串被销毁时,即在该表达式的末尾,它将被销毁。
您正在返回一个指向已经被破坏的内存的指针。
答案 1 :(得分:4)
看起来mPath.string()
按值返回字符串。一旦FileReference :: c_str()返回,该临时字符串对象就被破坏,因此其c_str()变为无效。使用这样的模型,如果不为字符串引入某种类或静态级变量,则无法创建c_str()
函数。
考虑以下备选方案:
//Returns a string by value (not a pointer!)
//Don't call it c_str() - that'd be misleading
String str() const
{
return mPath.string();
}
或
void str(String &s) const
{
s = mPath.string();
}
答案 2 :(得分:0)
表达式
OutputDebugString(file.path().c_str())
和
OutputDebugString(file.c_str())
类似,因为它们都在临时c_str()
对象上有效地调用std::string
方法并尝试使用该调用的结果。第一个将其直接称为file.path().c_str()
子表达式。第二个更隐式地做到了:在FileReference::c_str()
方法内部。
在第一种情况下,std::string
调用显式创建临时file.path()
对象作为整个表达式的直接部分。根据语言规则,该临时对象的生命周期延伸到整个表达式的末尾,这就是c_str()
调用的临时和结果始终有效的原因。
在第二种情况下,在std::string
方法中创建临时FileReference::c_str()
对象。当此方法返回时,该临时对象将被销毁,这意味着FileReference::c_str()
返回指向“死”数据的指针。这就是所谓“垃圾”的原因。