Win32 C++17 - system_category().message().c_str() 返回的指针立即消失...为什么?

Win32 C++17 - Pointer returned by system_category().message().c_str() dies immediately...why?

考虑以下代码:

#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
}

一个多小时以来,我一直在绞尽脑汁想弄清楚为什么会抛出这个愚蠢的异常。然后我终于决定向你们这些优秀的人咨询,发现 this SO answer 解释得很清楚:

The temporary returned by the conf() function call lives as long as the full expression it is part of, not for the length of the function containing the call.

当然我没有调用与那个问题的OP相同的函数,但我猜我失败的原因是一样的。但我在 超过 18 年 的编程生涯中从未遇到过这个问题!那么有人可以解释一下为什么 message() 函数返回的值只是暂时的,无法依赖吗?更重要的是:我该如何解决?

MTIA! :-)

编辑:刚刚意识到我可以使用 FormatMessage() 来代替,但我仍然想请解释一下这种行为。谢谢!

函数消息returns似乎是std::string(或std::basic_string)类型的临时对象。成员函数c_str返回的指针在临时对象存活时有效

避免未定义行为的方法之一是存储返回的字符串,例如

auto errMsg = system_category().message(GetLastError());

然后在需要时使用表达式 errMsg.c_str()

你检查过auto errMsg的类型了吗?我打赌它是const char*,到的。可能,死字符串

是的,您遇到了与 other question 相同的问题。在这种情况下,message() 返回一个 temporary std::string 对象 by value,它超出范围并被销毁在创建它的语句末尾的 ; 上。您正在获取指向临时文件内部数据的指针,然后在您有机会使用该指针之前临时文件被销毁,导致 未定义的行为 当您尝试使用该指针访问无效内存时.

您已经用这种方式编码了 18 年,这一事实非常令人不安。这个你应该早就遇到了

对此有两种可能的解决方案:

  1. 通过在获取指向其数据的指针之前将临时 std::string 对象保存到变量来扩展数据范围:
#include <windows.h>
#include <strsafe.h>

int main() {
    // ...many lines of code not related to the problem

    auto errMsg = system_category().message(GetLastError()); // <-- not c_str()!
    char buf[MAX_PATH];

    StringCchPrintfA(buf, MAX_PATH, "Function '%s' failed: %s", "funcName", errMsg.c_str()); // <-- use c_str() here!

    // ...more unrelated code
}
  1. 直接在 StringCchPrintfA() 语句中使用临时 std::string 及其数据指针,因此临时保留在范围内:
#include <windows.h>
#include <strsafe.h>

int main() {
    // ...many lines of code not related to the problem

    char buf[MAX_PATH];
    StringCchPrintfA(buf, MAX_PATH, "Function '%s' failed: %s", "funcName", system_category().message(GetLastError()).c_str());

    // ...more unrelated code
}