如何像L""一样将string转为const wchar_t*?解决wstring转指针疑问
问题背景
尝试用L""语法处理变量x时,编译器会将其展开为Lx,触发未定义错误,因此自定义了widen函数将std::string转为std::wstring,再尝试转为wchar_t*。
第一版代码及问题
#include <locale> #include <iostream> #include <string> #include <sstream> using namespace std ; wstring widen( const string& str ) { wostringstream wstm ; const ctype<wchar_t>& ctfacet = use_facet<ctype<wchar_t>>(wstm.getloc()) ; for( size_t i=0 ; i<str.size() ; ++i ) wstm << ctfacet.widen( str[i] ) ; return wstm.str() ; } int main() { const char* cstr = "sandbox.exe" ; const wchar_t* wcstr = widen(cstr).c_str() ; wcout << wcstr << L'\n' ; }
这段代码存在悬垂指针问题:widen(cstr)返回的临时std::wstring在语句结束后立即销毁,wcstr指向的内存已被释放,后续访问属于未定义行为。此外,返回的指针地址与L"sandbox.exe"的地址不同——这是正常现象,因为字符串字面量存储在只读数据段,而std::wstring的缓冲区在堆/栈内存中,存储位置天然不同。
第二版代码及观察
#include <locale> #include <iostream> #include <string> #include <sstream> using namespace std ; wstring widen( const string& str ) { wostringstream wstm ; const ctype<wchar_t>& ctfacet = use_facet<ctype<wchar_t>>(wstm.getloc()) ; for( size_t i=0 ; i<str.size() ; ++i ) wstm << ctfacet.widen( str[i] ) ; return wstm.str() ; } int main() { const char* cstr = "sandbox.exe" ; const std::wstring widestring = widen(cstr); const wchar_t* wcstr = widestring.c_str(); wcout << wcstr << L'\n' ; }
此版本中widestring的内容与L"sandbox.exe"完全一致,但c_str()返回的指针地址仍与字面量不同。核心疑问:如何不使用c_str()将std::wstring转为wchar_t*?
解决方案
1. 使用data()或&str[0](C++11及以后)
C++11标准后,std::wstring::data()与c_str()等价,返回指向内部缓冲区的指针,且缓冲区以\0结尾。此外,也可以用&widestring[0]获取指针(注意:空字符串时&widestring[0]是未定义行为,data()则安全返回指向\0的指针)。
示例:
const std::wstring widestring = widen(cstr); const wchar_t* wcstr1 = widestring.data(); const wchar_t* wcstr2 = &widestring[0]; // 仅当widestring非空时安全
注意:这两个方法返回的指针生命周期与widestring绑定,若widestring被销毁、修改或扩容,指针会失效。
2. 手动分配内存复制内容(需管理内存)
如果需要一个独立于std::wstring生命周期的wchar_t*,可以手动分配内存并复制内容:
const std::wstring widestring = widen(cstr); wchar_t* wcstr = new wchar_t[widestring.size() + 1]; wcscpy(wcstr, widestring.c_str()); // 使用wcstr... // 必须手动释放内存,避免泄漏 delete[] wcstr;
此方法需要手动管理内存,容易出错,仅在特殊场景下使用。
关键说明
std::wstring的内部缓冲区地址与字符串字面量地址不同是完全正常的,二者存储位置不同(字面量在只读数据段,wstring缓冲区在动态内存),无需纠结地址差异,只要内容正确即可。
内容的提问来源于stack exchange,提问作者kaan kaya

