array.push_back gives some odd iterator error

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

array.push_back gives some odd iterator error

Post by krama757 »

Hey guys, while using the following code I got an error during the push_back statement at the end.

What do you think could be a problem in this code? I'm really stumped.

Code: Select all

IGUIListBox* listBox;
	int prevItemSelected;
	STalkInfo tempInfo2;
	//char* tempString = new char();
	wchar_t tempWString[100];
	std::string tempString; 
	
	//First find out which box element was previously selected
	listBox = (IGUIListBox*)(irrGuiEnv->getRootGUIElement()->getElementFromId(301));
	prevItemSelected = listBox->getSelected();

	if(prevItemSelected != -1){
		tempInfo2.level = sInfo[prevItemSelected].level+1;		//level places this one as a child of the previously selected item
		for(int i = 0; i<tempInfo2.level; i++){
			tempString += "   ";
		}
		tempString += "New Item";
		mbstowcs(tempWString, tempString.c_str(), tempString.size()+1);
		//tempWString = wcscat_s(tempWString, L"New Item");
		listBox->addItem(tempWString);							//add a placeholder to the list box for the new item

		tempInfo2.number = 1;
		for(int i = 0; i<sInfo.size(); i++){
			if(sInfo[i].level == tempInfo2.level)
				tempInfo2.number++;			//set the number according to how many other elements there are already in this level
		}

		tempInfo2.prevSpeakerNum = sInfo[prevItemSelected].number;
		tempInfo2.speakerId = !sInfo[prevItemSelected].speakerId;
		
		//Convert the wchar_t version of the list box item's text to std::string stored in the sInfo struct
		
		//tempString = new char(wcslen(listBox.getListItem(listBox.getSelected())) + 1);
		//wcstombs( tempString , listBox.getListItem(listBox.getSelected()), wcslen(listBox.getListItem(listBox.getSelected())) );

		tempInfo2.sStatement = "New Item";

		//sInfo can now equal all the info on the newly created item
		sInfo.push_back(tempInfo2);
	}else{
		cout<<"You didnt select a parent thread!"<<endl;
	}
The declaration of the STalkInfo structure is here:

Code: Select all

struct STalkInfo{
	int speakerId;		///0 for npc and 1 for player
	int level; 
	int number; 
	int prevSpeakerNum;
	std::string sStatement;
};
The declaration of the array sInfo is here:

Code: Select all

array<STalkInfo> sInfo;
At the end of the code, STalkInfo tempInfo2 has the proper values of items. There arent any glaring errors that I can see. But when I try to push_back, the program points to an error in xutility.h which is part of the MSVC Express libraries.
Last edited by krama757 on Tue Jan 23, 2007 8:50 pm, edited 2 times in total.
Klasker
Posts: 230
Joined: Thu May 20, 2004 8:53 am
Contact:

Post by Klasker »

I have experienced problems with array<T> when using complex types that require a constructor call. Try making it an array of pointers (array<STalkInfo*>) instead and see if it helps. You can use set_free_on_destroyed or something like to that make it free them automatically when the array is destroyed.
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

What line in xutility? What is the call stack when this happens?

A priori, I'd say you're mixing incompatible runtime libraries. Either a debug/release confusion or you're not using multithreaded (debug) dll as your runtime library setting for all of your application's components.


You can test this theory when you remove sStatement from STalkInfo, or change it to some POD type. When it works afterwards, then the problem is because of the above reason.
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

Post by krama757 »

Well, depending on what I do, it gives me errors in different places.

I changed the project settings to Multi-threaded Debug Dll and kept the code the same. At this point I get a error in irrArray.h here:

Code: Select all

        // destruct old data
		for (u32 j=0; j<used; ++j)
			allocator.destruct(&old_data[j]);
When I try to use pointers only, it doesnt allow me to declare and later use because tempInfo2 hasnt been initialized. If I have no constructor for the structure what can I do? :

Code: Select all

STalkInfo* tempInfo2;
The error it gives me for when I try tempInfo2 = new STalkInfo() is:

Code: Select all

Unhandled exception at 0x7c812a5b in NPC_Conversation.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012f9f0..
So the code doesnt proceed at all.

The really wierd thing is that in my constructer, everything works fine even though its almost a mirror of whats in this function. Look at this:

Code: Select all

CGui::CGui()
{
	STalkInfo tempInfo;

	irrGuiEnv->addStaticText(L"First give the NPC a name. Press ENTER anytime you change a editbox. Click + to add a response in the tree", rect<s32>(24, 16, 544, 32), false, false, 0);

	IGUIListBox *list1 = irrGuiEnv->addListBox(rect<s32>(24, 48, 992, 390), 0, 301);
		list1->addItem(L"Npc: Welcome, please edit this box to begin making the conversation");
		tempInfo.level = 1;
		tempInfo.number = 1;
		tempInfo.prevSpeakerNum = 0;
		tempInfo.speakerId = 0;
		tempInfo.sStatement = "Welcome, please edit this box to begin making the conversation";
		sInfo.push_back(tempInfo);

	irrGuiEnv->addButton(rect<s32>(24, 400, 48, 424), 0, 1, L"+");

	IGUIComboBox *combo1 = irrGuiEnv->addComboBox(rect<s32>(64, 400, 176, 424), 0, 101);

		combo1->addItem(L"NPC");

		combo1->addItem(L"Player");

	irrGuiEnv->addEditBox(L"Enter text for conversation here", rect<s32>(192, 408, 992, 432), true, 0, 201);

	irrGuiEnv->addStaticText(L"Never add multiple NPC responses to the same Player response", rect<s32>(24, 440, 176, 560), false, true, 0);

	irrGuiEnv->addEditBox(L"", rect<s32>(72, 576, 185, 595), true, 0, 202);

	irrGuiEnv->addStaticText(L"Name: ", rect<s32>(24, 576, 56, 592), false, false, 0);

	//Destroy sInfo 
	sInfo.set_free_when_destroyed(true);
}
Klasker
Posts: 230
Joined: Thu May 20, 2004 8:53 am
Contact:

Post by Klasker »

When you use pointers you have to create the object explicitly. Like this:

Code: Select all

tmpInfo2 = new STalkInfo;
And, of course, you need to use "->" to address members instead of ".". If you ever remove an item from the array, make sure you delete it when you don't need it anymore, because the array only frees them when the array itself gets destroyed.

Here is the entire code, using pointers:

Code: Select all

IGUIListBox* listBox;
   int prevItemSelected;
   STalkInfo* tempInfo2;
   //char* tempString = new char();
   wchar_t tempWString[100];
   std::string tempString;
   
   //First find out which box element was previously selected
   listBox = (IGUIListBox*)(irrGuiEnv->getRootGUIElement()->getElementFromId(301));
   prevItemSelected = listBox->getSelected();

   if(prevItemSelected != -1){
      tempInfo2 = new STalkInfo;
      tempInfo2->level = sInfo[prevItemSelected]->level+1;      //level places this one as a child of the previously selected item
      for(int i = 0; i<tempInfo2->level; i++){
         tempString += "   ";
      }
      tempString += "New Item";
      mbstowcs(tempWString, tempString.c_str(), tempString.size()+1);
      //tempWString = wcscat_s(tempWString, L"New Item");
      listBox->addItem(tempWString);                     //add a placeholder to the list box for the new item

      tempInfo2->number = 1;
      for(int i = 0; i<sInfo.size(); i++){
         if(sInfo[i]->level == tempInfo2->level)
            tempInfo2->number++;         //set the number according to how many other elements there are already in this level
      }

      tempInfo2->prevSpeakerNum = sInfo[prevItemSelected]->number;
      tempInfo2->speakerId = !sInfo[prevItemSelected]->speakerId;
      
      //Convert the wchar_t version of the list box item's text to std::string stored in the sInfo struct
      
      //tempString = new char(wcslen(listBox.getListItem(listBox.getSelected())) + 1);
      //wcstombs( tempString , listBox.getListItem(listBox.getSelected()), wcslen(listBox.getListItem(listBox.getSelected())) );

      tempInfo2->sStatement = "New Item";

      //sInfo can now equal all the info on the newly created item
      sInfo.push_back(tempInfo2);
   }else{
      cout<<"You didnt select a parent thread!"<<endl;
   } 
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

What happens when you remove sStatement from STalkInfo? Does it work then or not?

Also please paste the first part of your buildlog.htm, the part with compiler and linker settings.
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

Post by krama757 »

When I remove sStatement and use Klaskers code it gives me a std::bad alloc when I call tempInfo2 = new STalkInfo;

Here are the compiler settings:

Code: Select all

For the C/C++: 

/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_VC80_UPGRADE=0x0600" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Fp".\Debug/main.pch" /Fo".\Debug/" /Fd".\Debug/" /W3 /nologo /c /ZI /TP /errorReport:prompt


For the Linker: 
/OUT:".\Debug/NPC_Conversation.exe" /INCREMENTAL /NOLOGO /MANIFEST /MANIFESTFILE:".\Debug\NPC_Conversation.exe.intermediate.manifest" /DEBUG /PDB:".\Debug/main.pdb" /SUBSYSTEM:CONSOLE /MACHINE:X86 /ERRORREPORT:PROMPT odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib

Klasker
Posts: 230
Joined: Thu May 20, 2004 8:53 am
Contact:

Post by Klasker »

I think the bug is elsewhere in your code. Try posting some more code. (Btw you don't need to send me PMs I can find the thread by myself.)
Post Reply