wstring::c_str() contains garbage

我的梦境 提交于 2020-01-24 23:45:31

问题


I have a std::wstring decode(const char *s) function.

I use it like this:

const char *src = "some string";
const wchar_t *result = decode(src).c_str();

I always get garbage in result[0], sometimes in result[1] too.

I dont get garbage when I use it in another way:

std::wstring res = decode(src);
const wchar_t *result = res.c_str();

My decode function defined as below, and it does it's job. Only problem is calling code(above).

std::wstring decode(const char *s, UINT cp=CP_ACP)
{
    if(s == NULL)
        return std::wstring();
    int length = ::MultiByteToWideChar(cp, 0, s, -1, NULL, 0 );
    wchar_t *buf = new wchar_t[length];
    ::MultiByteToWideChar(cp, 0, s, -1, buf, length);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

I use Visual C++ 2008 SP1 to compile.


回答1:


const wchar_t *result = decode(src).c_str();

The return value of decode is a temporary value and is destroyed after the call to c_str(). Thus result points to freed memory.

So either

  • extend the lifetime of the return value (assign it to a local variable, for example)
  • copy the result



回答2:


12.2 Temporary objects [class.temporary]

3 When an implementation introduces a temporary object of a class that has a non-trivial constructor (12.1, 12.8), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor (12.4). Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.

So, do not use a temporary after it was destroyed, like in your first example.




回答3:


The answers to your specific problems can be found in both the good answers provided. Since the question title was simply wstring::c_str() contains garbage I'm going to point out a way to get a result that is correct without the decode function.

Microsoft added a number of ATL conversion macros and classes to convert between wide character (Unicode) and MBCS (Ascii). They are available on VS2008. The supported conversions can be found in the MSDN Documentation:

ATL 7.0 introduces several new conversion classes and macros, providing significant improvements over the existing macros. The names of the new string conversion classes and macros take the form: CSourceType2[C]DestinationType[EX].

[snip]

SourceType/DestinationType

A = ANSI character string.

W = Unicode character string.

T = Generic character string (equivalent to W when _UNICODE is defined, equivalent to A otherwise).

OLE = OLE character string (equivalent to W).

The [EX] is optional and often used if you don't want to specify the size of the default internal buffer that gets used with the macro.

In your case the conversion macro CA2W (convert Ascii to Widechar) should do what you want. You only need to #include <atlbase.h> to use them. These macros take 2 parameters - the string to be converted and the code page (defaults to CP_ACP if not specified)

In your case you had:

std::wstring res = decode(src);
const wchar_t *result = res.c_str();

Using the ATL conversion macros you could do it this way:

std::wstring res = CA2W(src, CP_ACP);
const wchar_t *result = res.c_str();

Since the macros default to Ansi Code Page you can also leave off CP_ACP like this:

std::wstring res = CA2W(src);
const wchar_t *result = res.c_str();

Regarding the issue with the temporary objects the same thing applies to the class returned by these macros. Microsoft even documents this issue with an incorrect usage example in the link provided earlier:

// Example 3 
// Incorrect use of conversion macros. 
void ExampleFunction3(LPCWSTR pszW)
{
    // Create a temporary instance of CW2A, 
    // save a pointer to it and then delete 
    // the temportary instance.
    LPCSTR pszA = CW2A(pszW);
    // The pszA in the following line is an invalid pointer, 
    // as the instance of CW2A has gone out of scope.
   ExampleFunctionA(pszA);
}


来源:https://stackoverflow.com/questions/26304239/wstringc-str-contains-garbage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!