Dinna_Dawg
Dinna_Dawg

Reputation: 13

Passing LPCWSTR by reference

I was tidying up some code I wrote a long time ago, putting it into methods and the like, when I tried this to get an input string and LPCWSTR from an input prompt for a directory search.

void GetInfo(string &stdStr, LPCWSTR &wStr)
{
    cout << endl << "Enter String: ";
    getline(cin, stdStr);

    string sTempP = stdStr;

    #ifdef UNICODE
        std::wstring wTemp = s2ws(stdStr);
        wStr = wTemp.c_str();
    #else
        wStr = stdStr.c_str();
    #endif

    stdStr = sTempP;

    return;
}

And when I call

string directoryName;
LPCWSTR directory_Name;
GetInfo(directoryName, directory_Name);

the std string works fine but the LPCWSTR gives me garbage. They both work fine inside of the method, so I was wondering how come passing this string by reference works oddly?

Oh, and I tried writing a function that converts a std::string to a LPCWSTR and assigning the variable to that but that was also weird. The code works fine if defined in the main body, it's only when inside a function that I get problems.

Thanks,

Fraser

Upvotes: 1

Views: 3553

Answers (5)

Aaron Klotz
Aaron Klotz

Reputation: 11585

There are several things that I would improve in that code, but your main problem is that LPCWSTR is a pointer to a string, not a string. You are assigning a new pointer value to wStr, but by the time your function has returned, the memory that is being pointed to is no longer valid.

When UNICODE is defined, that memory is no longer valid once wTemp is no longer in scope. In the case where UNICODE is not defined, the pointer is no longer valid because it points to the data contained inside stdStr at the time that you called c_str(). When you execute

stdStr = sTempP;

The pointer that was previously returned to you can no longer be considered valid.

LPCWSTR is just a Windows typedef for const wchar_t *. You'd be better off changing the signature of GetInfo to something like this:

void GetInfo(string &stdStr, wstring &wStr);

And changing the code accordingly. Assuming that you need to derive a LPCWSTR to call a Win32 API function or something, here's how you can do it:

string directoryName;
wstring directory_Name;
GetInfo(directoryName, directory_Name);
LPCWSTR p_directory_Name = directory_Name.c_str();

Upvotes: 4

aschepler
aschepler

Reputation: 72473

The c_str() methods return pointers which are managed by the objects you called them on. The sTempP and wTemp objects are local to the GetInfo function, so by the time that function has returned, both those objects have been destroyed, and the pointers previously returned by c_str() are no good.

It looks like LPCWSTR is designed for C programming, not C++. So you'll have to either find an object type you can use instead of LPCWSTR, or do some extra managing with allocating space and copying data and deallocating again.

Upvotes: 0

Steve Townsend
Steve Townsend

Reputation: 54178

LPCWSTR is just a pointer (defined in Windows headers) whereas std::string is a full-fledged C++ class.

This line therefore just modifies the input pointer value - you would need to copy the value byte by byte (std::copy or similar) from stdStr.c_str() to the LPCWSTR-addressed memory for this to work (assuming enough space, and correct null termination).

 wStr = stdStr.c_str();

This is also dangerous because when the string goes out of scope the c_str() returned value is not longer valid, leaving your LPCSWTR pointing to memory that will cause undefined behaviour when accessed.

As you can see, there's not a lot of point in passing raw pointers by reference if you only plan to use the memory that was already there. This would only be useful if you planned to replace the input pointer with the address of a new area of memory that remained valid on return (with attendant ownership headaches, so still not a great idea).

Upvotes: 0

Kirill V. Lyadvinsky
Kirill V. Lyadvinsky

Reputation: 99715

The result of stdStr.c_str() became invalid right after stdStr = sTempP.

Upvotes: 0

Yippie-Ki-Yay
Yippie-Ki-Yay

Reputation: 22854

LPCWSTR is just a typedef for const wchar_t*.

You could use a std::wstring and std::wstring::c_str() to retrieve LPCWSTR.

Also, if you wish, there is a very easy way to convert the std::string to std::wstring using a specialized facade for the boost::lexical_cast.

Upvotes: 0

Related Questions