我很好奇下面的代码是否正确?我在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内部缓冲区