预分配 std::string 以传递到 WinAPI
Preallocating std::string to pass into a WinAPI
我想知道下面的代码是否正确?我 运行 它在较旧版本的 VS 2008 上,用于 Windows-only 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()
returns const wchar_t *
和 GetWindowText()
请求 LPTSTR
,这不是 const
缓冲区。类型转换可以吗?
不,根据 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
另请参阅:writing directly to std::string internal buffers
我不能代表 VS2008,但是大多数 pre-C++11 遵循 &str[0] + i == str.data() + i
的 C++11 规则,所以 &str[0]
可以工作并且不需要任何casts1,这比颠覆类型系统和标准要安全得多。请小心,因为不允许覆盖字符串后的空终止符,即使使用另一个空终止符也是如此。如果您不能为 VS2008 保证这一点,那么 std::vector<wchar_t>
将是首选解决方案。
但是,你还有另一个问题。 reserve
不会阻止越界访问 str
的未定义行为。边界基于 size()
,而不是 capacity()
。您需要将 reserve
更改为 resize
。
即便如此,你还有另一个问题。 GetWindowTextLength
不包括空终止符。您必须在该调用后的代码中使用 nLn + 1
。
随着所做的更改,这将适用于任何符合 C++11 的实现,包括一些 pre-C++11 实现,并忽略错误检查:
int nLnWithNul = GetWindowTextLength(hWnd);
std::wstring str(nLnWithNul, '[=10=]'); // bit of a shorthand for the resize call
int nCopiedLn = GetWindowText(hWnd, &str[0], nLnWithNul);
str.resize(nCopiedLn);
最后一个 resize
调用处理了比 nLnWithNul
短的复制标题。例如,如果标题在 GetWindowTextLength
被调用后缩小。调整大小后,字符串将仅包含复制的文本,不包括其后的任何 NUL 字符。
1:参见my previous question的答案。
我想知道下面的代码是否正确?我 运行 它在较旧版本的 VS 2008 上,用于 Windows-only 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()
returns const wchar_t *
和 GetWindowText()
请求 LPTSTR
,这不是 const
缓冲区。类型转换可以吗?
不,根据 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
另请参阅:writing directly to std::string internal buffers
我不能代表 VS2008,但是大多数 pre-C++11 遵循 &str[0] + i == str.data() + i
的 C++11 规则,所以 &str[0]
可以工作并且不需要任何casts1,这比颠覆类型系统和标准要安全得多。请小心,因为不允许覆盖字符串后的空终止符,即使使用另一个空终止符也是如此。如果您不能为 VS2008 保证这一点,那么 std::vector<wchar_t>
将是首选解决方案。
但是,你还有另一个问题。 reserve
不会阻止越界访问 str
的未定义行为。边界基于 size()
,而不是 capacity()
。您需要将 reserve
更改为 resize
。
即便如此,你还有另一个问题。 GetWindowTextLength
不包括空终止符。您必须在该调用后的代码中使用 nLn + 1
。
随着所做的更改,这将适用于任何符合 C++11 的实现,包括一些 pre-C++11 实现,并忽略错误检查:
int nLnWithNul = GetWindowTextLength(hWnd);
std::wstring str(nLnWithNul, '[=10=]'); // bit of a shorthand for the resize call
int nCopiedLn = GetWindowText(hWnd, &str[0], nLnWithNul);
str.resize(nCopiedLn);
最后一个 resize
调用处理了比 nLnWithNul
短的复制标题。例如,如果标题在 GetWindowTextLength
被调用后缩小。调整大小后,字符串将仅包含复制的文本,不包括其后的任何 NUL 字符。
1:参见my previous question的答案。