I'm trying to port my code from using MFC's CString
to std::string
for Microsoft Windows platform. And I'm curious about something. Say in the following example:
CString MakeLowerString(LPCTSTR pStr)
{
CString strLower = pStr ? pStr : L"";
CharLower(strLower.GetBuffer()); //Use WinAPI
strLower.ReleaseBuffer();
return strLower;
}
I use strLower.GetBuffer() to obtain a writable buffer to be passed to the CharLower API. But I don't see a similar method in std::string
.
Am I missing something? And if so, how would you overwrite the method above using std::string
?
On my new job we do not use MFC - but luckily std lib and C++11 - so I've come up to the same question as c00000fd. Thanks to BitTickler's answer I came up with the idea of using the string's internal buffer for Win32-APIs via the &s[0]
resp. &s.front()
catch.
Assuming that you have a string which shall become shortened by a Win32-API function - e.g. ::PathRemoveFileSpec(path)
- you may follow this approach:
std::string path( R("?(C:\TESTING\toBeCutOff)?") );
::PathRemoveFileSpec( &path.front() ); // Using the Win32-API
// and the the string's internal buffer
path.resize( strlen( path.data() ) ); // adjust the string's length
// to the first \0 character
path.shrink_to_fit(); // optional to adjust the string's
// capacity - useful if you
// do not plan to modify the string again
Unicode Version:
std::wstring path( LR("?(C:\TESTING\toBeCutOff)?") );
::PathRemoveFileSpec( &path.front() ); // Using the Win32-API
// and the the string's internal buffer
path.resize( wcslen( path.data() ) ); // adjust the string's length
// to the first \0 character
path.shrink_to_fit(); // optional to adjust the string's
// capacity - useful if you
// do not plan to modify the string again
Assuming that you have a string which shall become extended or filled by a Win32-API function - e.g. ::GetModuleFileName(NULL, path, cPath)
to retrieve your executable's path - you may follow this approach:
std::string path;
path.resize(MAX_PATH); // adjust the internal buffer's size
// to the expected (max) size of the
// output-buffer of the Win32-API function
::GetModuleFileName( NULL, &path.front(), static_cast<DWORD>( path.size() ) );
// Using the Win32-API
// and the the string's internal buffer
path.resize( strlen( path.data() ) ); // adjust the string's length
// to the first \0 character
path.shrink_to_fit(); // optional to adjust the string's
// capacity - useful if you
// do not plan to modify the string again
Unicode Version:
std::wstring path;
path.resize(MAX_PATH); // adjust the internal buffer's size
// to the expected (max) size of the
// output-buffer of the Win32-API function
::GetModuleFileName( NULL, &path.front(), static_cast<DWORD>( path.size() ) );
// Using the Win32-API
// and the the string's internal buffer
path.resize( wcslen( path.data() ) ); // adjust the string's length
// to the first \0 character
path.shrink_to_fit(); // optional to adjust the string's
// capacity - useful if you
// do not plan to modify the string again
When you finally shrink-to-fit the string then you need just one more line of code when extending the string's internal buffer compared with the MFC alternative, when shrinking the string it has nearly the same overhead.
The advantage of the std::string
approach in contrast to the CString
approach is that you do not have to declare an additional C-String pointer variable, you just work with the official std::string
methods and with one strlen
/wcslen
function.
My approach shown above only works for the shrinking variant when the resulting Win32-API buffer is null-terminated, but for that very special case in which the Win32-API returns an unterminated string, then - similar to the CString::ReleaseBuffer
method - you must explicitly know and specify the new string/buffer length by path.resize( newLength )
- just like path.ReleaseBuffer( newLength )
for the CString
alternative.
void GetString(char * s, size_t capacity)
{
if (nullptr != s && capacity > 5)
{
strcpy_s(s,capacity, "Hello");
}
}
void FooBar()
{
std::string ss;
ss.resize(6);
GetString(&ss[0], ss.size());
std::cout << "The message is:" << ss.c_str() << std::endl;
}
As you can see, you can use the the "old school c- pointer" both for feeding strings into a legacy function as well as use it as an OUT parameter. Of course, you need to make sure, there is enough capacity in the string for it to work etc.
Depending on your requirements, you can use one or more of the following:
std::string::operator[]()
. This function returns a character at a given index without bounds checking.
std::string::at()
. This function returns a character at a given index with bounds checking.
std::string::data()
. This functions returns an const
pointer to the raw data.
std::string::c_str()
. This function returns the same value as std::string::data()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With