【问题标题】:LPCWSTR corruption if const char* returned from a function如果从函数返回 const char*,则 LPCWSTR 损坏
【发布时间】:2019-07-20 21:22:24
【问题描述】:

我遇到了一个非常奇怪的问题。

我希望在 Windows 上使用 MessageBox(扩展为 MessageBoxW)输出一个简单的字符串。

以下是我正在使用的方法:

void MainWindow::ShowMessageBox( const std::wstring& title,const std::wstring& message ) const
{
    MessageBox( hWnd,message.c_str(),title.c_str(),MB_OK );
}

std::wstring ConversionHelpers::s2ws(const std::string& s)
{
    int len;
    int slength = (int)s.length() + 1;

    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);

    wchar_t* buf = new wchar_t[len];

    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);

    delete[] buf;
    return r;
}

void DebugHelpers::MsgBox(MainWindow& window, const char* title, const char* message)
{
    std::string t(title);
    std::string m(message);

    window.ShowMessageBox(ConversionHelpers::s2ws(t), ConversionHelpers::s2ws(m));
}

这行得通:

MsgBox(wnd, "Test", std::string("Hello").c_str());

这不起作用:

const char* get_hello()
{
    return std::string("Hello").c_str();
}

MsgBox(wnd, "Test", get_hello());

“不起作用”是指我得到了大量奇怪的字符。

我知道在此示例中不需要转换,但在我的实现中,这是必要的。但这并不能回答关于奇怪的问题。

我对两者都做同样的事情,但是使用一种方法来返回值,而不是直接访问它。

【问题讨论】:

  • 字符串字面量转换为wstring,尝试在它前面放一个L,L"test"
  • std::wstring 中的w 代表wchar_t 和宽字符。它们不同于使用char 的窄字符。
  • @chris:你是对的。
  • 犯了一个小错误,更新问题
  • @RickyFisher 调试那些转换函数。这是完成大部分工作的地方。

标签: c++


【解决方案1】:

get_hello() 创建的 std::string 在退出时超出范围时会被释放,而返回的 char* 在您甚至可以使用之前就指向无效内存。

最好让get_hello()返回std::string,然后调用者可以在返回的std::string上调用c_str()添加需要:

std::string get_hello()
{
    return std::string("Hello");
}

MsgBox(wnd, "Test", get_hello().c_str());

【讨论】:

    【解决方案2】:

    std::string::c_str 返回的指针指向std::string 对象拥有的内存。当关联的std::string 对象被销毁时,该内存被释放。任何进一步尝试访问它都会导致未定义的行为。

    匿名临时对象(例如使用std::string("Hello").c_str() 创建的std::string 对象)一直存在到创建它们的完整表达式的末尾。这实质上意味着它们在下一个分号处超出范围。

    当您调用MsgBox(wnd, "Test", std::string("Hello").c_str()); 时,临时的std::string 会一直存在,直到MsgBox 函数调用结束。当它超出范围时,MsgBox 已使用它,并且没有其他尝试访问由c_str 返回的指针所指向的内存。一切都很好。

    在第二种情况下,您再次创建一个临时的 std::string 对象。这次它只存在到get_hello 中的return 语句结束。当控制返回到调用函数时,在get_hello 中创建的临时std::string 已经消失,您返回的指针悬空,指向无效内存。

    【讨论】:

    • 我应该使用 memcpy 或类似的东西来获取 const char* 的副本,而不是使用由 c_str() 指向的现已删除的值生成的副本吗?
    • 您应该只返回std::string 对象并让它管理内存,正如@RemyLebeau 在他们的回答中显示的那样。您可以分配自己的内存,但这样做会更复杂、更容易出错,而且效率可能更低。
    猜你喜欢
    • 2012-05-05
    • 2012-05-26
    • 1970-01-01
    • 2012-02-18
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    相关资源
    最近更新 更多