将 std::string 转换为 std::wstring 时,C++17 codecvt 抛出“错误转换”

Posted

技术标签:

【中文标题】将 std::string 转换为 std::wstring 时,C++17 codecvt 抛出“错误转换”【英文标题】:C++17 codecvt throw "bad conversion" when convert std::string to std::wstring 【发布时间】:2019-11-04 09:34:24 【问题描述】:

我写了一个名为UString的字符串类,我想要的是可以将std::string转换为std::wstring,也可以将std::wstring转换为std::string

我使用的是c++17中的库,所以我写的代码如下。

在 UString.h 中:

public:
        UString(std::string s);                         
    UString(std::wstring ws);   
private:
    std::string str;                                
    std::string WTS(const std::wstring & wstr);
    std::wstring STW(const std::string & str);
public:
        std::wstring w_str();                           
    const wchar_t* wc_str();

在 UString.cpp 中:

UString::UString(std::string s)

    str = s;

UString::UString(std::wstring ws)

    str = WTS(ws);

std::string UString::WTS(const std::wstring & wstr)

    std::string ret;
    try 
        std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
        ret = wcv.to_bytes(wstr);
    
    catch (const std::exception& e) 
        std::cerr << e.what() << std::endl;
    
    return ret;

std::wstring UString::STW(const std::string & str)

    std::wstring ret;
    try 
        std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
        ret = wcv.from_bytes(str);
    
    catch (const std::exception & e) 
        std::cerr << e.what() << std::endl;
    
    return ret;

std::wstring UString::w_str()

    return STW(str);

const wchar_t* UString::wc_str()

    return STW(str).c_str();

它应该像这样工作:

UString ustr="test"; //the value should be "test"
UString ustr2=L"test2"; //the value should be "test2"
wcout<<ustr.w_str()<<endl; //the value should be "test"
cout<<ustr.wc_str()<<endl; //the value should be "test"

在 linux、GCC 8.0.1 中,该类工作正常,但在 Windows、Visual Studio 2017 中,当我使用 UString::w_str()UString::wc_str() 时,它无法工作并引发“错误转换”错误。 我应该怎么做才能完成这项工作?

【问题讨论】:

看起来你的代码中有 UB,返回一​​个指向堆栈上某物的指针 值得注意的是,在 Windows 中,wchar_t 代表一个 UTF16 字符,而在所有其他操作系统中,它代表一个 32 位代码点。不幸的是,这使得 wchar_t 在系统之间完全不兼容。我强烈怀疑您需要条件代码来处理 windows 案例。 Can't reproduce.w_str() call 对我有用,并产生预期的数据。 std::cout &lt;&lt; wc_str() 打印存储在指针中的地址,因为您将 wchar_t* 输出到窄流中。如果您改用std::wcout,程序将表现出未定义的行为。 【参考方案1】:

wc_str() 返回一个悬空指针;调用者对其返回值的任何使用都会表现出未定义的行为,方法是在对象的生命周期结束后访问对象。

STW(str) 生成一个临时文件,然后c_str() 获取一个指向由该临时文件管理的数据的指针。然后临时对象被销毁,数据随之被删除,指针变得悬空。

【讨论】:

可能根本不提供wc_str() 成员。 w_str() 应该足够了。 但是w_str()函数也不能工作,它会抛出bad_conversion错误。 正如我在之前的评论中提到的,can't reproduce

以上是关于将 std::string 转换为 std::wstring 时,C++17 codecvt 抛出“错误转换”的主要内容,如果未能解决你的问题,请参考以下文章

将 std::__cxx11::string 转换为 std::string

将 std::string 转换为 std::wstring 时,C++17 codecvt 抛出“错误转换”

如何将 std::string 转换为 NSString?

C++ .NET 将 System::String 转换为 std::string

如何将“char”转换为“std::string”? [复制]

将 int 转换为 std::string