How do I get a writable C buffer from a std :: string?

I'm trying to convey your code using MFC CString

in std::string

the Microsoft Windows platform. And I'm interested in something. Let's say in the following example:

CString MakeLowerString(LPCTSTR pStr)
{
    CString strLower = pStr ? pStr : L"";
    CharLower(strLower.GetBuffer());        //Use WinAPI
    strLower.ReleaseBuffer();

    return strLower;
}

      

I am using strLower. GetBuffer () to get a writeable buffer that will be passed to CharLower . 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

?

+3


source to share


4 answers


We don't use MFC in my new job, but luckily std lib and C ++ 11, so I ended up with the same question as c00000fd. Thanks to BitTickler's answer, I came up with the idea of ​​using an internal internal buffer for Win32-API via &s[0]

resp. &s.front()

catch.

Using a Win32-API function that shrinks the internal string buffer

Suppose you have a string that will be truncated using a Win32-API function. ::PathRemoveFileSpec(path)

- you can follow this approach:

std::string path( R("?(C:\TESTING\toBeCutOff)?") );
::PathRemoveFileSpec( &path.front() ); // Using the Win32-API
                                       // and the the string internal buffer
path.resize( strlen( path.data() ) );  // adjust the string 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 internal buffer
path.resize( wcslen( path.data() ) );  // adjust the string 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

      

Using a Win32-API function that expands the internal string buffer



Assuming you have a string that needs to be expanded or populated with a Win32-API function. ::GetModuleFileName(NULL, path, cPath)

to get your executable path - you can follow this approach:

std::string path;
path.resize(MAX_PATH);                 // adjust the internal buffer 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 internal buffer
path.resize( strlen( path.data() ) );  // adjust the string 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 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 internal buffer
path.resize( wcslen( path.data() ) );  // adjust the string 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, you will need one more line of code when expanding the internal string buffer compared to the MFC alternative, it has almost the same overhead when shrinking the string.

The advantage of the approach std::string

as opposed to the approach CString

is that you don't need to declare an additional C-String pointer variable, you just work with the official methods std::string

and with a single strlen

/ wcslen

. My approach shown above only works for the shortening variant when the resulting Win32-API buffer ends at zero, but for this special case where the Win32-API returns an inexhaustible string then - like the method CString::ReleaseBuffer

- you must explicitly know and specify the new string length / buffer on path.resize( newLength )

- exactly the same as path.ReleaseBuffer( newLength )

for the alternative CString

.

+4


source


The accepted lowercase way std::string

is:

#include <algorithm>
#include <string> 

std::string data = "Abc"; 
std::transform(data.begin(), data.end(), data.begin(), ::tolower);

      

You really can't get around iterating through each character. The initial Windows API call will iterate over characters internally.



If you need to get toLower()

for a language version other than the standard "C" locale, you can use instead:

std::string str = "Locale-specific string";
std::locale loc("en_US.UTF8");  // desired locale goes here
const ctype<char>& ct = use_facet<ctype<char> >(loc);
std::transform(str.begin(), str.end(), str.begin(), std::bind1st(std::mem_fun(&ctype<char>::tolower), &ct));

      

To answer your question directly and minus any context, you can call str.c_str()

to get const char *

(LPCSTR) with std::string

. You cannot directly convert std::string

to char *

(LPTSTR); this is by design and undermines some of the very motives for use std::string

.

+2


source


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 "old school pointer" both to feed strings to the legacy function and to be used as an OUT parameter. Of course, you need to make sure there is enough capacity in the row to work, etc.

+2


source


Depending on your requirements, you can use one or more of the following:

+1


source







All Articles