9

I have the following block of code:

for( CarsPool::CarRecord &record : recs->GetRecords())
{
  LVITEM item;
  item.mask = LVIF_TEXT;
  item.cchTextMax = 6;

  item.iSubItem = 0;
  item.pszText = (LPSTR)(record.getCarName().c_str()); //breakpoint on this line.
  item.iItem = 0;
  ListView_InsertItem(CarsListView, &item);

  item.iSubItem = 1; 
  item.pszText = TEXT("Available");
  ListView_SetItem(CarsListView, &item);

  item.iSubItem = 2;
  item.pszText = (LPSTR)CarsPool::EncodeCarType(record.getCarType());
  ListView_SetItem(CarsListView, &item);
}

The information from Visual Studio Debugger is here:

enter image description here

Why isn't the program able to read the characters from string?

A test has shown me that it works in this way:

MessageBox(hWnd, (LPSTR)(record.getCarName().c_str()), "Test", MB_OK);
Victor
  • 13,914
  • 19
  • 78
  • 147
  • 1
    Is `getCarName` returning a copy? In that case the temporary returned is destroyed at the end of the expression, leaving the pointer returned by `c_str()` dangling. See e.g. [here](http://stackoverflow.com/questions/4214153/lifetime-of-temporaries) – user786653 Sep 22 '13 at 17:13
  • The debugger isn't able to read the information because you are still at the point **before** the assignment took place. `0xcccccccc` is the value Microsoft's CRT fills allocated memory with. If you see this sequence you have uninitialized memory. – IInspectable Sep 22 '13 at 17:16
  • I wanted that breakpoint because the output "looks empty" in my list view. – Victor Sep 22 '13 at 17:17

2 Answers2

5

getCarName likely returns a temporary. After the assignment the temporary object is destroyed and the pointer item.pszText points to invalid memory. You must ensure that the string object is valid during the call to ListView_InsertItem.

std::string text(record.getCarName());
item.iSubItem = 0;
item.pszText = const_cast<LPSTR>(text.c_str());
item.iItem = 0;
ListView_InsertItem(CarsListView, &item);

The const_cast is an artifact of the fact that the Windows API uses the same structure to set and retrieve information. When invoking ListView_InsertItem the structure is immutable, however there is no way to reflect that in the language.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • +1 this is preferable to using `strcpy` or similar "raw" C functions as long as the list view control makes a copy of the string (which IIRC is the default). – user786653 Sep 22 '13 at 17:28
3

It looks like you're trying to use the value of a C++ "string" in a C/Win32 call.

stdstring.c_str() is the correct way to do it.

... BUT ...

You should strcpy() the string to a temp variable, then make the Win32 call with the temp variable.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • 2
    @Victor - It's entirely up to the individual who answers how to write the answer. I don't think this question needs code to be answered properly (and, actually, he _did_ provide code). – Carey Gregory Sep 22 '13 at 17:24