C++ Win32 C++;17-system_category()返回的指针。message().c_str()立即死亡…为什么?
考虑以下代码:C++ Win32 C++;17-system_category()返回的指针。message().c_str()立即死亡…为什么?,c++,string,winapi,scope,c++17,C++,String,Winapi,Scope,C++17,考虑以下代码: #include <windows.h> #include <strsafe.h> int main() { // ...many lines of code not related to the problem auto errMsg = system_category().message(GetLastError()).c_str(); char buf[MAX_PATH]; // Throws an access
#include <windows.h>
#include <strsafe.h>
int main() {
// ...many lines of code not related to the problem
auto errMsg = system_category().message(GetLastError()).c_str();
char buf[MAX_PATH];
// Throws an access violation exception
StringCchPrintfA(buf, MAX_PATH, "Function '%s' failed: %s", "main", errMsg);
// ...more unrelated code
}
#包括
#包括
int main(){
//…许多与问题无关的代码行
auto errMsg=system_category().message(GetLastError()).c_str();
char buf[MAX_PATH];
//引发访问冲突异常
StringCchPrintfA(buf,最大路径,“函数'%s'失败:%s”,“主”,errMsg);
//…更多不相关的代码
}
一个多小时以来,我一直在绞尽脑汁,想弄明白到底为什么会抛出这个愚蠢的例外。然后我最终决定向你们这些优秀的人咨询这件事,并发现这非常清楚地解释了这一点:
conf()函数调用返回的临时表达式的有效期与它所属的完整表达式的有效期相同,而与包含该调用的函数的长度无关
当然,我并没有调用与问题OP相同的函数,但我猜我失败的原因是相同的。但在编程的18年中,我从未遇到过这个问题!那么,有人能解释一下为什么从message()
函数返回的值只是临时的,不能依赖吗?更重要的是:如何修复它?
MTIA!:-)
编辑:我刚刚意识到我可以使用
FormatMessage()
来代替,但我仍然希望您能解释一下这种行为。谢谢 函数消息似乎返回类型为std::string
(或std::basic_string
)的临时对象。当临时对象处于活动状态时,成员函数c_str
返回的指针有效
避免未定义行为的方法之一是存储返回的字符串,例如
auto errMsg = system_category().message(GetLastError());
然后使用表达式
errMsg.c_str()
,如果需要。是否检查了自动errMsg
的类型?我打赌它是const char*
,到了最前面。可能是死字符串是的,您的问题与问题相同。在这种情况下,message()
通过值返回一个临时的std::string
对象,该对象超出范围并在上被销毁代码>位于创建它的语句的末尾。您正在获取指向临时对象内部数据的指针,然后在您有机会使用该指针之前,临时对象将被销毁,从而在您尝试使用该指针访问无效内存时导致未定义行为
事实上,您已经以这种方式编码了18年,这是非常令人不安的。你早就应该遇到这个问题了
有两种可能的解决方案:
在获取指向其数据的指针之前,通过将临时std::string
对象保存到变量来扩展数据的范围:
#包括
#包括
int main(){
//…许多与问题无关的代码行
auto errMsg=system_category().message(GetLastError());//您得到的是临时字符串值,因此它在表达式末尾被销毁。由system_category()返回的std::string
(推测)在语句结尾处不再存在。因此c_str()的调用
提供一个指向数据的指针,该指针由一个立即不存在的对象管理。调用c_str()
不会神奇地延长返回的std::string
的生命。相反,将字符串保存在另一个变量中,并对该变量调用c_str()
(例如std::string catMsg=system_category().message(GetLastError());auto errMsg=catMsg.c_str();
catMsg将一直存在,直到包含作用域(
{})结束,也将结束。
errMsg`。如果你已经用这种方式编码18年了,那么你可能已经留下了错误,在你离开后让其他人来修复。感谢你的解释,现在它是有意义的。至于你的建议,我在发帖之前尝试过这两种方法,但都没有帮助。后一种方法实际上是我第一次尝试,因为我“我一直是一个狂热的代码高尔夫球手:帕尔索我想澄清一下我对“18年编程”的看法”。并非所有这些都是用C/C++编写的,事实上可能只有一年左右的时间,那是作为一名学生。尽管如此,我也很难相信我以前从未遇到过这个问题。也许我遇到过,只是不记得了。@Kenny83“我在发布之前尝试过这两种方法,但都没有帮助”-然后你对它们做了一些错误的事情,因为两种方法在正确使用时都很好。我站在正确的立场上!我一定尝试了后一个例子的轻微变化,因为乍一看它似乎是一样的,但将其逐字复制到我的项目中效果非常好!非常感谢!!在我离开你之前的最后一件事是:做y你知道用宽字符串可靠地执行此操作的方法吗?似乎system\u category()。。。