正在预分配要传递到WinAPI中的std::字符串

Preallocating std::string to pass into a WinAPI

本文关键字:WinAPI 中的 std 字符串 预分配      更新时间:2023-10-16

我很好奇下面的代码是否正确?我在VS2008的旧版本上运行它,用于一个仅限Windows的C++项目。

我的目标是在std::string中预先分配内存,以便将其传递到WinAPI中,知道所需的字符大小:

//'hWnd' = window handle
int nLn = GetWindowTextLength(hWnd);
//Text variable to collect text in
std::wstring str;
str.reserve(nLn);
GetWindowText(hWnd, (LPTSTR)str.data(), nLn);

我在这里担心的是str.data()返回const wchar_t *,而GetWindowText()请求LPTSTR,而不是const缓冲区。在那里可以进行类型转换吗?

我不能代表VS2008,但大多数C++11之前的版本都遵循&str[0] + i == str.data() + i的C++11规则,因此&str[0]可以工作,不需要任何类型转换1,这是一条比颠覆类型系统和标准安全得多的途径。只是要小心,因为不允许在字符串后面覆盖null终止符,即使使用另一个null终止符也是如此。如果您不能为VS2008保证这一点,那么std::vector<wchar_t>将是首选解决方案。

然而,你还有另一个问题。CCD_ 9并没有阻止其越界访问CCD_ 10的未定义行为。边界基于size(),而不是capacity()。您需要将reserve更改为resize

即便如此,你还有另一个问题。GetWindowTextLength不包括空终止符。您必须在该调用之后的代码中使用nLn + 1

随着所做的更改,这将适用于任何一致的C++11实现,包括一些C++11之前的实现,并忽略错误检查:

int nLnWithNul = GetWindowTextLength(hWnd);
std::wstring str(nLnWithNul, ''); // bit of a shorthand for the resize call
int nCopiedLn = GetWindowText(hWnd, &str[0], nLnWithNul);
str.resize(nCopiedLn);

最后一个resize调用处理复制的标题短于nLnWithNul。例如,如果标题在调用GetWindowTextLength后收缩。调整大小后,字符串将只包含复制的文本,后面不包括任何NUL字符。


1:看我上一个问题的答案。

不,根据C++标准,您不能这样做。但如果你使用std::vector<wchar_t>而不是std::wstring:,你可以做到这一点

int nLn = GetWindowTextLength(hWnd);
std::vector<TCHAR> str(nLn); // size, not reserve()
int size = GetWindowText(hWnd, str.data(), nLn);
str.resize(size); // will make empty in case of error

另请参阅:直接写入std::string内部缓冲区