使用WinAPI,您经常会遇到一些将LPWSTR或LPSTR作为参数的方法。有时这个指针应该是指向缓冲区的指针,例如:
int GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount);
将std::wstring
用于此类缓冲区是否是一个好主意,特别是我强烈需要生成std::wstring
作为结果,并且不能将其替换为vector<wchar_t>
?
std::wstring myWrapper(HWND hWnd){
auto desiredBufferSize = GetWindowTextLengthW(hWnd);
std::wstring resultWstr;
resultWstr.resize(desiredBufferSize);
auto ret = GetWindowText(hWnd,
const_cast<wchar_t*>(resultWstr.data()), // const_cast
resultWstr.size());
// handle return code code
return resultWstr;
}
data()
和c_str()
字符串方法都返回const指针,因此我们必须使用const_cast
来删除constness,这有时是一个坏符号。在这种情况下,这是一个好主意吗?我能做得更好吗?
答案 0 :(得分:2)
从const char*
到std::string
的自动类型转换,但不是其他方式。
字符'\ 0'对于std :: string不是特殊的。
&s[0]
用于写访问确保字符串大小(不仅仅是容量)足以支持C风格。
s.c_str()
仅限访问权限仅在下一次非常量方法调用之前有效。
代码示例:
const int MAX_BUFFER_SIZE = 30; // Including NULL terminator.
string s(MAX_BUFFER_SIZE, '\0'); // Allocate enough space, NULL terminated
strcpy(&s[0], "This is source string."); // Write, C++11 only (VS2010 OK)
printf("C str: '%s'\n", s.c_str()); // Read only: Use const whenever possible.
答案 1 :(得分:2)
很有必要选择标准的wstring。然而,扔掉const ......永远不会好。
这里有一个临时字符串包装器,它自动创建一个缓冲区,将其指针传递给winapi函数,并将缓冲区的内容复制到你的字符串中并干净利落地消失:
auto ret = GetWindowText(hWnd,
tmpstr (resultWstr, desiredBufferSize),
resultWstr.size());
此解决方案适用于任何Windows API 函数,该函数在返回之前写入字符指针(即没有同步)。
它是如何运作的?
它基于C ++标准§12.2第3点:“临时对象被破坏作为评估全表达式的最后一步(词法上)包含创建它们的点。(...)值销毁临时对象的计算和副作用只与full-expression有关,而与任何特定的子表达无关。“。
这是实施:
typedef std::basic_string<TCHAR> tstring; // based on microsoft's TCHAR
class tmpstr {
private:
tstring &t; // for later cpy of the result
TCHAR *buff; // temp buffer
public:
tmpstr(tstring& v, int ml) : t(v) { // ctor
buff = new TCHAR[ml]{}; // you could also initialize it if needed
std::cout << "tmp created\n"; // just for tracing, for proof of concept
}
tmpstr(tmpstr&c) = delete; // No copy allowed
tmpstr& operator= (tmpstr&c) = delete; // No assignment allowed
~tmpstr() {
t = tstring(buff); // copy to string passed by ref at construction
delete buff; // clean everyhing
std::cout<< "tmp destroyed"; // just for proof of concept. remove this line
}
operator LPTSTR () {return buff; } // auto conversion to serve as windows function parameter without having to care
};
如您所见,第一行使用了typedef,以便与多个Windows编译选项兼容(例如Unicode or not)。但是,当然,如果您愿意,可以将tstring
和TCHAR
替换为wstring
和wchar_t
。
唯一的缺点是你必须重复缓冲区大小作为参数tmpstr构造函数和windows函数的参数。但这就是你为这个功能写一个wrepper的原因,不是吗?
答案 2 :(得分:0)
对于字符串缓冲区,为什么不只使用char数组? :)
DWORD username_len = UNLEN + 1;
vector<TCHAR> username(username_len);
GetUserName(&username[0], &username_len);
公认的解决方案是一个很好的例子。