Search code examples
c++11memory-managementsmart-pointerswstringwidechar

wcstombs & allocating memory for character array on heap


I'm reading a file with a single wide character line in it. But, I never know how long it is going to be. I've read this into a std::wstring, inString, and have managed to create the multi byte string out of thin air (Q1 - are these called r-values?). Q2 - Now, how do I allocate memory for this in the heap and obtain a smart pointer to it ? I do not want to use new or malloc (and call free or delete eventually) or any constant to store it on the stack (for I can never know the max length). Q3 - Can I make use of the make_shared or make_unique function templates here ? Q4 - To be specific, can I get a pointer like shared_ptr<char> pointing to the char array allocated on the heap ?

I tried something like the following,

std::shared_ptr<char> MBString(const_cast<char*>(std::string(inString.begin(), inString.end()).c_str()));

it did not work. I tried a few suggestions on the internet but I don't know how to do it yet.

Q5 - Let alone Wide char to multi -byte conversion, in general, how do I allocate an arbitrary length char string on the heap and get a smart pointer to it ?

std::wfstream inFile(L"lengthUnkown.txt", std::ios::in);
std::wstring inString;
inFile >> inString;
std::wcout << inString << std::endl; //prints correctly
std::cout << (const_cast<char*>(std::string(inString.begin(), inString.end()).c_str())) << std::endl; //this prints the line correctly as expected
//convert wide character string to multi-byte on the heap pointed, to by MBString 
//std::cout << MBString << std::endl; //I want to print the multi-byte string like this
return 0;

Solution

  • Not resource optimal but reliable:

    wchar_t* mb2wstr(const char* inval) {
        size_t size = std::strlen(inval);
        #define OUTSZ (size+1)*sizeof(wchar_t)
        auto buf = (wchar_t*)std::malloc(OUTSZ);
        std::memset(buf, 0, OUTSZ);
        std::setlocale(LC_CTYPE,""); //  необходима, чтобы отработала "mbstowcs"
        size = std::mbstowcs(buf, inval, size);
        if ( size == (size_t)(-1) ) {
            std::free(buf);
            buf = nullptr;
        } else {
            buf = (wchar_t*)std::realloc(buf,OUTSZ);
        }
        return buf;
        #undef OUTSZ
    }
    
    char* wstr2mb(const wchar_t* inval) {
        size_t size = std::wcslen(inval);
        #define OUTSZ (size+1)*MB_CUR_MAX // Maximum length of a multibyte character in the current locale
        auto buf = (char*)std::malloc(OUTSZ);
        std::memset(buf, 0, OUTSZ);
        std::setlocale(LC_CTYPE,""); //  необходима, чтобы отработала "wcstombs"
        size = std::wcstombs(buf, inval, size*sizeof(wchar_t));
        if ( size == (size_t)(-1) ) {
            std::free(buf);
            buf = nullptr;
        } else {
            buf = (char*)std::realloc(buf,size+1);
        }
        return buf;
        #undef OUTSZ
    }
    
    const std::string pwchar2string(const wchar_t* inval) {
        char* tmp = wstr2mb(inval);
        string out{tmp};
        std::free(tmp);
        return out;
    }
    const std::wstring pchar2wstring(const char* inval) {
        wchar_t* tmp = mb2wstr(inval);
        wstring out{tmp};
        std::free(tmp);
        return out;
    }
    
    const wstring string2wstring(const string& value) {
        return pchar2wstring(value.c_str());
    }
    const string wstring2string(const wstring& value) {
        return pwchar2string(value.c_str());
    }
    const wchar_t* char2wchar(const char* value) {
        return pchar2wstring(value).c_str();
    }
    const char* wchar2char(const wchar_t* value) {
        return pwchar2string(value).c_str();
    }