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>
代替它的情况下?
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
来去除const,这有时是一个坏兆头。在这种情况下,这是一个好主意吗?我能做得更好吗?
使用字符串作为C字符串
从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, ' '); // 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.
选择漂亮的标准wstring很诱人。然而,扔掉const永远都不好。。。
这里有一个临时字符串包装器,它自动创建一个缓冲区,将指针传递给winapi函数,并将缓冲区的内容复制到您的字符串中,然后干净地消失:
auto ret = GetWindowText(hWnd,
tmpstr (resultWstr, desiredBufferSize),
resultWstr.size());
此解决方案适用于任何在字符指针返回之前写入字符指针的windows API函数(即无assync)。
它是如何工作的
它基于C++标准§12.2第3点:"临时对象被销毁是评估完整表达式的最后一步,完整表达式(从词汇上)包含了创建它们的点。(…)销毁临时对象的值计算和副作用只与完整表达式相关,而与任何特定的子表达式无关。"。
这里是实现:
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 createdn"; // 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,以便与几个窗口编译选项兼容(例如,Unicode或非Unicode)。当然,如果您愿意,您可以将tstring
和TCHAR
替换为wstring
和wchar_t
。
唯一的缺点是必须将缓冲区大小作为参数tmpstr构造函数和windows函数的参数来重复。但这就是为什么你要为函数写一个wrapper,不是吗?
对于字符串缓冲区,为什么不只使用char数组?:)
DWORD username_len = UNLEN + 1;
vector<TCHAR> username(username_len);
GetUserName(&username[0], &username_len);
公认的解决方案是过度思考的好例子。
- std::带有自定义缓冲区的 iostream 不允许我写入
- istream std::cin如何修改自定义istream缓冲区
- 在共享缓冲区内存中创建 ::std::string 对象
- 是否可以将 std::basic_ifstream 和 std::basic_ofstream 与自定义缓冲区一起使用?
- std::vector::assign/std::vector::operator=(const&) 是否保证在"this"中重用缓冲区?
- 如何将文件的一部分读取到std::list缓冲区?
- 在 std::string::end() 和 std::string::capacity() 之间使用缓冲区
- std::ifstream.read() 不会向我的缓冲区返回任何内容
- 输出操纵器 std::ends 是否向输出缓冲区添加空字符?
- 调整我的std :: string时,角色缓冲区会发生什么
- std::字符串与字节缓冲区(C++的差异)
- STD ::向量如何调整其内部缓冲区大小
- 在C 中,是否有可能在不兼容类型的std ::向量对象之间传输不同类型的缓冲区
- 我可以做一个循环,直到“std::cin”在输入缓冲区中看到“”字符
- 缓冲区刷新究竟是如何工作的(std::endl 和 之间的区别)?
- C++如何检查std::cin缓冲区是否为空
- 如何使用 std::istringstream 获取正确的缓冲区大小以进行数据解析
- 初始化的std ::阵列从指针优雅地变成缓冲区
- 别名,用于使用 std::aligned_union 和 std::aligned_union 进行小型缓冲区优化
- 如何使用 std::make_shared 创建动态大小缓冲区