简体   繁体   中英

LPCWSTR corruption if const char* returned from a function

I'm experiencing a very strange issue.

I'm looking to output a simple string using MessageBox (expands to MessageBoxW) on Windows.

Here are the methods I'm using:

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));
}

This works:

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

This doesn't work:

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

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

By 'doesn't work', I mean I'm getting a ton of weird characters.

I know the conversion isn't necessary in this example but in my implementation, it is necessary. That doesn't answer the question about the strangeness though.

I'm doing the exact same thing with both, but one uses a method to return the value rather than accessing it directly.

The std::string that get_hello() creates is freed when it goes out of scope upon exit, leaving the returned char* pointing at invalid memory before you can even use it.

It would be better to make get_hello() return the std::string instead, and then the caller can call c_str() on the returned std::string add needed:

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

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

The pointer returned by std::string::c_str points to memory owned by the std::string object. When the associated std::string object is destroyed, that memory is freed. Any further attempt to access it results in undefined behavior.

Anonymous temporary objects (such as the std::string object created with std::string("Hello").c_str() ) live until the end of the full expression in which they were created. That essentially means they go out of scope at the next semicolon.

When you call MsgBox(wnd, "Test", std::string("Hello").c_str()); , the temporary std::string survives until the end of the MsgBox function call. By the time it goes out of scope MsgBox is done using it, and nothing else attempts to access the memory pointed to by the pointer returned by c_str . Everything is fine.

In you second case, you create a temporary std::string object again. This time it only survives until the end of the return statement in get_hello . By the time control returns to the calling function the temporary std::string created in get_hello is gone, and the pointer you returned is left dangling, pointing to invalid memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM