Reputation: 13
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
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
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
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
Reputation: 99715
The result of stdStr.c_str()
became invalid right after stdStr = sTempP
.
Upvotes: 0
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