A common question I have been asked many times goes along these lines: “I need to pass a C++ string as input parameter to a Windows Win32 C API function. In modern C++ code, should I pass an STL string or a string view?”
Let’s start with some refinements and clarifications.
First, assuming the Windows C++ code is built in Unicode UTF-16 mode (which has been the default since Visual Studio 2005), the STL string class would be std::wstring, and the corresponding “string view” would be std::wstring_view.
Moreover, since wstring objects are, in general, not cheap to copy, I would consider passing them via const&. Use reference (&) to avoid potentially expensive copies, and use const, since these string parameters are input parameters, and they will not be modified by the called function.
So, the two competing options are typically:
// Use std::wstring passed by const&
SomeReturnType DoSomething(
/* [in] */ const std::wstring& s,
/* other parameters */
)
{
// Call some Win32 API passing s
...
}
// Use std::wstring_view (passing by value is just fine)
SomeReturnType DoSomething(
/* [in] */ std::wstring_view sv,
/* other parameters */
)
{
// Call some Win32 API passing sv
...
}
So, which form should you pick?
Well, that’s a good question!
In general, I would say that if the Win32 API you are wrapping/calling takes a pointer to a null-terminated C-style string (i.e. a const wchar_t*/PCWSTR/LPCWSTR parameter), then you should pick std::wstring.
An example of that is the SetWindowText Windows API. Its prototype is like this:
// In Unicode builds, SetWindowText expands to SetWindowTextW
BOOL SetWindowTextW(
HWND hWnd,
LPCWSTR lpString
);
When you write some code like this:
SetWindowText(hWndName, L"Connie"); // Unicode build
the SetWindowText(W) API is expecting a null-terminated C-style string. If you pass a std::wstring object, like this:
std::wstring name = L"Connie";
SetWindowText(hWndName, name.c_str()); // Works fine!
the code will work fine. In fact, the wstring::c_str() method is guaranteed to return a null-terminated C-style string pointer.
On the other hand, if you pass a string view like std::wstring_view in that context, you’ll likely get some subtle bugs!
To learn more about that, you may want to read my article: The Case of string_view and the Magic String.
Try experimenting with the above API and something like “Connie is learning C++” and string views!

On the other hand, there are Win32 APIs that accept also a pointer to some string characters and a length. An example of that is the LCMapStringEx API:
int LCMapStringEx(
LPCWSTR lpLocaleName,
DWORD dwMapFlags,
LPCWSTR lpSrcStr, // <-- pointer
int cchSrc, // <-- length (optional)
/* ... other parameters */
);
As it can be read from the official Microsoft documentation about the 4th parameter cchSrc, this represents (emphasis mine):
“(the) Size, in characters, of the source string indicated by lpSrcStr. The size of the source string can include the terminating null character, but does not have to.
(…) The application can set this parameter to any negative value to specify that the source string is null-terminated.”
In other words, the aforementioned LCMapStringEx API has two “input” working modes with regard to this aspect of the input string:
- Explicitly pass a pointer and a (positive) size.
- Pass a pointer to a null-terminated string and a negative value for the size.
If you use the API in working mode #1, explicitly passing a size value for the input string, the input string is not required to be null-terminated!
In this case, you can simply use a std::wstring_view, as there is no requirement for null-termination for the input string. And a std::[w]string_view is basically a pointer (to string characters) + a size.
Of course, you can still use the “classic” C++ option of passing std::wstring by const& in this case, as well. But, you also have the other option to safely use wstring_view.
One thought on “Passing C++ STL Strings vs. String Views as Input Parameters at the Windows C API Boundary”