C ++使用std :: string,std :: wstring作为缓冲区 [英] C++ using std::string, std::wstring as a buffer

查看:127
本文介绍了C ++使用std :: string,std :: wstring作为缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆