C ++使用std :: string,std :: wstring作为缓冲区 [英] C++ using std::string, std::wstring as a buffer
问题描述
使用WinAPI,你经常会遇到一些获取LPWSTR或LPSTR作为参数的方法。有时这个指针应该是指向缓冲区的指针,例如:
int GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount );
这是一个好主意使用 std :: wstring
这样的缓冲区,在特殊情况下我强烈需要产生 std :: wstring
作为结果,不能替换为 vector< wchar_t& / code>例如?
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());
//句柄返回代码代码
return resultWstr;
}
两个 data()
和 c_str()
字符串方法返回const指针,因此我们必须使用 const_cast
删除constness,坏的标志。在这种情况下是个好主意吗?我可以做得更好吗?
这是很好的标准wstring。
这里是一个临时字符串包装器,它自动创建一个缓冲区,将其指针传递给winapi函数,并将缓冲区的内容复制到您的字符串并彻底清除:
auto ret = GetWindowText(hWnd,
tmpstr(resultWstr,desiredBufferSize),
resultWstr.size());
此解决方案适用于写入字符指针的任何Windows API
b
它基于C ++标准§12.2第3点:临时对象被销毁作为评估完整表达式的最后一步,(词法)包含它们被创建的点。 ..)破坏临时对象的值计算和副作用仅与完全表达式相关联,而不与任何特定的子表达式相关联。。
这里是实现:
typedef std :: basic_string< TCHAR> ; tstring; //基于微软的TCHAR
类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] {}; //你也可以初始化它如果需要
std :: cout<< tmp created\\\
; //仅用于跟踪,用于概念证明
}
tmpstr(tmpstr& c)= delete; //不允许复制
tmpstr& operator =(tmpstr& c)= delete; //不允许赋值
〜tmpstr(){
t = tstring(buff); // copy to string pass by ref at construction
delete buff; // clean everyhing
std :: cout<< tmp destroyed; //只是为了证明概念。删除此行
}
运算符LPTSTR(){return buff; } //自动转换作为windows函数参数,而不必关心
};
如您所见,第一行使用typedef,以便与多个窗口编译兼容选项(例如 Unicode或不是)。但当然,你可以用 wstring $ c $替换
tstring
和 TCHAR
c>和 wchar_t
。
唯一的缺点是必须重复缓冲区大小作为参数tmpstr构造函数和windows函数的参数。但这就是为什么你写的wrepper的功能,不是吗?
Using WinAPI you can often encounter some methods getting LPWSTR or LPSTR as a parameter. Sometimes this pointer should be a pointer to buffer in fact, for example:
int GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount);
Is it a good idea to use std::wstring
for such buffers, in particular case I strongly need to produce std::wstring
as result and cannot replace it with vector<wchar_t>
for example?
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;
}
Both data()
and c_str()
string methods return const pointer, so we must use const_cast
to remove constness, which sometimes is a bad sign. Is it a good idea in such case? Can I do better?
It's tempting to go for nice standard wstring. However it's never good to cast away const...
Here a temporary string wrapper that automatically creates a buffer, passes its pointer to the winapi function, and copies the content of the buffer to your string and disapears cleanly:
auto ret = GetWindowText(hWnd,
tmpstr (resultWstr, desiredBufferSize),
resultWstr.size());
This solution works with any windows API function that writes to a character pointer before it returns (i.e. no assync).
How does it work ?
It's based on C++ standard §12.2 point 3 : "Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created. (...) The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.".
Here it's implementation:
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
};
As you can see, the first line uses a typedef, in order to be compatible with several windows compilation options (e.g. Unicode or not). But of course, you could just replace tstring
and TCHAR
with wstring
and wchar_t
if you prefer.
The only drawback is that you have to repeat the buffer size as parameter tmpstr constructor and as parameter of the windows function. But this is why you're writing a wrepper for the function, isn't it ?
这篇关于C ++使用std :: string,std :: wstring作为缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!