最近在用 imgui 写一个数据对比工具,里面需要使用 Win32 函数来选择文件路径。相关代码差不多是这个样子:
std::string GetOpenFilePath(const std::string &title) {
char path[MAX_PATH];
OPENFILENAME ofn;
ofn.lpstrTitle = title.c_str(); // 设置对话框标题
ofn.lpstrFile = path;
ofn.nMaxFile = MAX_PATH;
// ...
if (!GetOpenFileNameA(&ofn)) {
// error
return {};
}
return path;
}
由于在程序中使用了 utf8 编码,而 Win32 需要 GBK 编码,故需要处理编码转换的问题。所以代码改成了这样:
// 为了避免“谁来释放内存”这种问题,转换函数直接返回了 std::string
std::string GbkToUtf8(const std::string &gbk_str);
std::string Utf8ToGbk(const std::string &utf8_str);
std::string GetOpenFilePath(const std::string &title) {
// ...
ofn.lpstrTitle = Utf8ToGbk(title).c_str();
// ...
return GbkToUtf8(path);
}
结果导致对话框标题一直是乱码。这是因为: Utf8ToGbk(title)
返回了一个临时对象,临时对象在当前表达式求值完成时会被销毁。导致后面调用 GetOpenFileNameA
时,lpstrTitle
指向的字符串其实已经被销毁了!
关于临时对象的销毁时机,C++ 标准文件 N486 6.7.7 描述如下:
Temporary objects are destroyed as the last step in evaluating the full-expression (6.9.1) that (lexically) contains the point where they were created.
解决方法很简单,只要将临时对象变为局部对象即可。
- ofn.lpstrTitle = Utf8ToGbk(title).c_str();
+ std::string t = Utf8ToGbk(title);
+ ofn.lpstrTitle = t.c_str();
顺带一提,将临时对象(函数的返回值)赋值给局部变量,并不会导致额外的一次拷贝构造。这就是所谓的返回值优化(Return Value Optimization)。
标签:std,string,title,临时,ofn,lpstrTitle,str,一则,bug From: https://www.cnblogs.com/fchen99/p/16650619.html