2

I am creating a dynamic array of LPCWSTR, and want to assign values at run time. I have following code :

cin>>count
LPCWSTR * lpwcstrArray = new LPCWSTR[count]();

for (int i = 0; i < count; i++)
{
    // some logic to create different wstring on each iteration
    wstring tempWString = L"somerandomstuff";

    lpwcstrArray[i] = reinterpret_cast<LPSWSTR>tempWString.c_str();
}

Now if i access lpwcstrArray - all the indexs point at data of last string that was assigned.

I know this is not correct way to assign values, but i do not know the correct way.

l'-'l
  • 428
  • 1
  • 7
  • 18

3 Answers3

3

wstring tempWString is created and destroyed with each iteration of the loop.
You have dangling pointers in your lpwcstrArray and are experiencing undefined behaviour when you access one of them.
You need to allocate the space yourself or use a std::wstring as the array type instead of a LPCWSTR.

Beta Carotin
  • 1,659
  • 1
  • 10
  • 27
  • Thanks for the explanation, As I have to use LPCWSTR* , what is the right api to allocate memory here, i am new to c++ – l'-'l Jul 09 '15 at 23:06
  • You would use `new`. You can google it, and don't forget that you have to free the resources that you allocate using `delete`. – Beta Carotin Jul 09 '15 at 23:08
  • Thanks,Created an array instead to store wstring and then assign so that pointers point to valid memory. – l'-'l Jul 10 '15 at 07:15
  • Accepting Remy's answer, as it gives the solution. Unluckily we cannot accept more than 1. – l'-'l Jul 10 '15 at 07:18
1

You are storing pointers that point at the internals of temporary std::wstring objects. When those objects are destroyed on each loop iteration, your array is left with danging pointers. You need to dynamically allocate the individual strings instead, eg:

std::cin >> count
LPWSTR *lpwstrArray = new LPWSTR[count];

for (int i = 0; i < count; i++)
{
    // some logic to create different wstring on each iteration
    std::wstring tempWString = L"somerandomstuff";

    LPWSTR str = new WCHAR[tempWString.length()+1];
    const wchar_t *p = tempWString.c_str();
    std::copy(p, p+tempWString.length(), str);

    lpwstrArray[i] = str;
}

// use lpwstrArray as needed...

// don't forget to free the memory when you are done using it...
for (int i = 0; i < count; i++)
    delete[] lpwstrArray[i];
delete[] lpwstrArray;

Depending on what you are really trying to accomplish, something more like the following would be safer, at least if you just need read-only access to the strings (which you likely do, as the C in LPCWSTR stands for const, so the user of the array is not going to be modifying them):

std::cin >> count

std::vector<std::wstring> wstrArray(count);
for (int i = 0; i < count; i++)
{
    // some logic to create different wstring on each iteration
    wstrArray[i] = L"somerandomstuff";
}

std::vector<LPWSTR> lpwstrArray(count);
for (int i = 0; i < count; i++)
    lpwstrArray[i] = const_cast<wchar_t*>(wstrArray[i].c_str());

// use lpwstrArray as needed. if you need to pass it where an
// LPWSTR* is expected, you can use &lpwstrArray[0] for that...

// lpwstrArray and wstrArray will be freed automatically
// when they go out of scope...
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
-1

Try the approach

    std::wstring ws(_T("Hello"));
    LPCTSTR lps= (LPCTSTR)(ws.c_str());

    TRACE(lps);

Notes:

  • You should not use the W types directly (ex: LPCWSTR). Use the T types instead (ex: LPCTSTR). Why? Because they will automatically translate to the version they should be (LPCSTR for non-Unicode / ASCII; LPCWSTR for Unicode), depending on your project.

  • For the same reason you should surround your strings with _T() or precede them with an L.

  • Try to dive deep using "Go To Definition" successively beginning on LPCTSTR

  • See also the _tcscpy_s function documentation

sergiol
  • 4,122
  • 4
  • 47
  • 81
  • 1
    Your advice is backwards. You should *avoid* using the TCHAR-based APIs and use the Unicode APIs instead. Windows has been Unicode-based for almost 2 decades now. The TCHAR APIs are for legacy support for apps that have to support Windows 9x/ME. Also, `_T()` (and `TEXT()`) is not the same thing as `L"..."`. – Remy Lebeau Jul 10 '15 at 16:41
  • @RemyLebeau I am with the tchar.h file at hands. I see #define _T(x) __T(x) and #define __T(x) L ## x Explain me please what is different in terms of practical effect. Trying to Go To Definition of L always takes me to elsewhere, not the definition of this L. – sergiol Jul 10 '15 at 18:02
  • There is no definition of `L`, it is built in to the compiler itself as part of the C/C++ language. `_T()` and `L` "do the exact same thing" only when `_UNICODE` is defined, where `_T("x")` maps to `L"x"`. When `_UNICODE` is not defined, `_T("x")` maps to `"x"` instead. Passing L"x" directly to a `_TCHAR`-based API is wrong, you have to pass `_T("x")` instead so it maps correctly in both environments. That is what you need when you have to cross-compile a single codebase for both Ansi (Win9x/ME) and Unicode (NT4+) versions of Windows... – Remy Lebeau Jul 10 '15 at 18:44
  • ... It is pretty rare to actually need to do that nowadays, though. Especially when writing new code. Everything is Unicode now, and there is a performance hit whenever you call the older Ansi-based APIs, so they (and `TCHAR` itself) should be avoided whenever possible/feasible. – Remy Lebeau Jul 10 '15 at 18:45
  • @RemyLebeau: I removed the "Both options do the exact same thing" statement as a result of your observation. – sergiol Jul 13 '15 at 11:19