wstring :: c_str()包含垃圾

时间:2014-10-10 16:46:28

标签: c++ visual-studio-2008 temporary-objects

我有一个std::wstring decode(const char *s)功能。

我这样用:

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

我总是在result[0]中出现垃圾,有时也在result[1]

当我以另一种方式使用它时,我不会得到垃圾:

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

我的decode功能定义如下,它完成了它的工作。唯一的问题是调用代码(上图)。

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

我使用Visual C ++ 2008 SP1进行编译。

3 个答案:

答案 0 :(得分:7)

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

decode的返回值是一个临时值,在调用c_str()后会被销毁。因此result指向释放的记忆。

所以要么

  • 延长返回值的生命周期(例如,将其分配给局部变量)
  • 复制结果

答案 1 :(得分:5)

  

12.2临时对象[class.temporary]

     

3当实现引入具有非平凡构造函数(12.1,12.8)的类的临时对象时,它应确保为临时对象调用构造函数。类似地,应该使用非平凡的析构函数(12.4)调用析构函数。 临时对象在评估全表达式(1.9)的最后一步时被破坏,该表达式(词法上)包含创建它们的点。即使该评估以抛出异常结束,也是如此。销毁临时对象的值计算和副作用仅与完整表达式相关联,而不与任何特定子表达式相关联。

所以,不要在它被破坏后使用临时,就像在你的第一个例子中一样。

答案 2 :(得分:1)

您提供的好答案都可以找到您具体问题的答案。由于问题标题只是wstring::c_str() contains garbage,我将指出一种方法来获得正确的结果没有 decode函数。

Microsoft添加了许多 ATL 转换宏和类,以便在宽字符(Unicode)和MBCS(Ascii)之间进行转换。它们可在VS2008上使用。支持的转化可在MSDN Documentation

中找到
  

ATL 7.0引入了几个新的转换类和宏,相对于现有的宏提供了重大改进。新字符串转换类和宏的名称采用以下形式:   <强> C SourceType中的 2 [C] DestinationType [EX]。

[剪断]

  

SourceType / DestinationType

     
    

A = ANSI字符串。

         

W = Unicode字符串。

         

T =通用字符串(定义_UNICODE时等效于W,否则等效于A)。

         

OLE = OLE字符串(相当于W)。

  

[EX]是可选的,如果您不想指定与宏一起使用的默认内部缓冲区的大小,则经常使用它。

在你的情况下,转换宏CA2W(将Ascii转换为Widechar)应该做你想要的。您只需#include <atlbase.h>即可使用它们。这些宏需要2个参数 - 要转换的字符串和代码页(如果未指定,则默认为CP_ACP)

在你的情况下,你有:

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

使用ATL转换宏可以这样做:

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

由于宏默认为Ansi Code Page,您也可以像这样取消CP_ACP:

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

关于临时对象的问题,同样的事情适用于这些宏返回的类。 Microsoft甚至在前面提供的链接中使用了错误的用法示例来记录此问题:

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