I asked this question about a half hour ago, but the code had typos and I wasn't being very clear, so I've deleted and I'm trying again with a better format.
I'm getting a Segmentation Fault in my code, the problem seems to be at the function call if( (*trans).test((*this), *(*itr)) ) inside World::update():
void World::update(sf::Time dt)
{
mPlayer->setVelocity(0.f, 0.f);
while (!mCommandQueue.isEmpty()){
Command cmd = mCommandQueue.pop();
cmd.action(cmd.node, dt);
}
mSceneGraph.update(dt);
adaptPlayerPosition();
//Enemy Spawn engine
if (mSpawnTimer.getElapsedTime().asSeconds() >= SPAWN_INTERVAL && mEnemies.size() < MAX_NUM_ENEMIES){
float winX = mWindow.getDefaultView().getSize().x;
float winY = mWindow.getDefaultView().getSize().y;
float x = rand() % (int)winX;
float y = rand() % (int)winY;
spawnEnemy(x, y, EnemyType::Loner, IState::ILWander);
mSpawnTimer.restart();
}
// FSM update
IState::ID curEnemyStateID;
FState curEnemyState;
bool trigger = false;
ICondition triggeredtrans;
FState triggeredState;
for(auto itr = mEnemies.begin(); itr != mEnemies.end(); ++itr){
curEnemyStateID = (*itr)->getState();
// set curState to whatever the enemy's curState is
switch(curEnemyStateID){
case 0:
curEnemyState = LWander;
break;
default:
break;
}
auto tState = curEnemyState.getTransitionStates().begin();
for(auto trans = curEnemyState.getConditions().begin(); trans != curEnemyState.getConditions().end(); ++trans){
if( (*trans).test((*this), *(*itr)) ){
trigger = true;
triggeredState = (*tState);
break;
}
++tState;
}
if(trigger){
(*itr)->setState(IState::ILRushPlayer);
curEnemyState = LRushPlayer;
}
curEnemyState.getAction()->doAction((*this), *(*itr));
}
}
Context:
trans is an iterator for a std::vector<ICondition> conditions where each ICondition has a test(World& world, Enemy& enemy). itr is an iterator through a std::vector<Enemy*> that is held by World.
The conditions vector is filled in this function:
void World::initializeStates()
{
Wander LWanderAction;
LWander.setAction(LWanderAction);
DistFromPlayer LWanderCond1(30);
LWander.pushCondition(LWanderCond1);
LWander.pushTransitionState(LRushPlayer);
}
LWander is a state (FState) in my Finite State Machine. Wander is a class that inherits IAction, and setAction accepts an IAction parameter: FState::setAction(IAction iact)
DistFromPlayer is a class that inherits ICondition.
FState::pushCondition(ICondition icond) and FState::pushTransitionState(Fstate state) should take their arguments and push them to Fstate's conditions and states vectors. (A transition's condition and matching target state should be at the same indices in both)
LWander and LRushPlayer are both members of World.
And that should cover everything. I don't know why I'm getting a SegFault, but I'm assuming that the problem is with how things are pushed into LWander in World::initializeStates(). I should also note that the SegFault occurs right after the first enemy is spawned in my game, which is also the same update frame that runs (*trans).test(*this, **itr) for the first time. All Enemys start in the LWander state.
ICondition's virtual bool test(World& world, Enemy& enemy); is defined as:
bool ICondition::test(World& world, Enemy& enemy){
return false;
//returns false by default, overwritten later
}
and DistFromPlayer's bool test(World& world, Enemy& enemy); is defined as:
bool DistFromPlayer::test(World& world, Enemy& enemy)
{
std::cout << "DistFromPlayer (LWander's Transition) was reached\n";
return false;
}
and only contains a print statement for debugging purposes.
GDB's backtrace
#0 World::update (this=0x6464408, dt=...) at C:\...\World.cpp:97
#1 0x0040416b in GameState::update (this=0x64643f0, dt=...) at C:\...\GameState.cpp:22
#2 0x00402435 in StateStack::update (this=0x28fde0, dt=...) at C:\...\StateStack.cpp:19
#3 0x00403782 in Game::update (this=0x28fbc0, elapsedTime=...) at C:\...\Game.cpp:58
#4 0x004036a2 in Game::run (this=0x28fbc0) at C:\...\Game.cpp:48
#5 0x0040888b in main () at C:\...\main.cpp:7
I am suspecting tState iterator. You only initialize it with begin() and increment it. I can't find any test against end() of the appropriate container. Or is it safe because of some relation between curEnemyState.getTransitionStates() and curEnemyState.getConditions() which I don't realize?
Related
I'm working on a game and I'm trying to add collectables. I'm trying to remove the object from the list after the player has collided with it, but it ends up crashing and says:
Unhandled exception thrown: read access violation.
__that was 0xDDDDDDE9.
It says this on the for loop statement, but I think it has to do with the remove_if() function.
Here is my code:
for (sf::RectangleShape rect : world1.level1.brainFrag) {
collides = milo.sprite.getGlobalBounds().intersects(rect.getGlobalBounds());
if (collides == true) {
world1.level1.brainFrag.remove_if([rect](const sf::RectangleShape val) {
if (rect.getPosition() == val.getPosition()) {
return true;
}
else {
return false ;
}
});
brainFrag -= 1;
collides = false;
}
}
if (brainFrag == 0) {
milo.x = oldPos.x;
milo.y = oldPos.y;
brainFrag = -1;
}
I don't understand your approach, you loop the rects, then when you find the one you want to remove, you search for it again through list<T>::remove_if.
I think that you forgot about the fact that you can use iterators in addition to a range-based loop:
for (auto it = brainFrag.begin(); it != brainFrag.end(); /* do nothing */)
{
bool collides = ...;
if (collides)
it = world1.level1.brainFrag.erase(it);
else
++it;
}
This allows you to remove the elements while iterating the collection because erase will take care of returning a valid iterator to the element next to the one you removed.
Or even better you could move everything up directly:
brainFrag.remove_if([&milo] (const auto& rect) {
return milo.sprite.getGlobalBounds().intersects(rect.getGlobalBounds())
}
A side note: there's no need to use an if statement to return a boolean condition, so you don't need
if (a.getPosition() == b.getPosition()
return true;
else
return false;
You can simply
return a.getPosition() == b.getPosition();
I am asking this question from an Unreal Engine C++ code point of view but I am wondering if my problem is more to do with the nuances of C++'s way of operating.
I have a Unreal actor. A simple class that holds an array of my own structs and runs a timer which triggers my own function. This function passes a reference of the actors array to an asynchronous task.
This async task then goes to work, first creating a new struct, then adding two floats to its own internal TArray of floats and then adds that struct to the main actors array.
The problem:
After the async task has completed and I delete the actor from the level editor window, the system RAM is decreased as I call the Empty() function on the main actors array in the Destroyed() function but the RAM used by all of the structs (ie: The float array inside each struct) is left in memory and never cleared out.
Observations:
If I do not use an async task and run the same function inside the main thread ALL of the memory is cleared successfully.
If I do not create the struct inside the async task and instead initalize the array with a load of structs which in turn are initialized with N number of floats inside the main thread, then pass that as a reference to the async task which works on the data, then the memory is also cleared out successfully.
What I would like to happen
I would like to pass a reference of the main actors array of structs to the async task. The async task would then go to work creating the data. Once it is complete, the main actor would then have access to the data and when the actor is deleted in the level editor window, ALL of the memory would be freed.
The code:
The definition of the data struct I am using:
struct FMyDataStruct
{
TArray<float> ArrayOfFloats;
FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
FMyDataStruct(int32 FloatCount)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
~FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
};
The main actors definition of the array I am using:
TArray<FMyDataStruct> MyMainArray;
The main actors custom function I am running:
//CODE 1: This part DOES empty the RAM when run (ie: Run on main thread)
/*for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}*/
//CODE 2: This does NOT empty the RAM when run. The two floats * 50,000,000 are left in system memory after the actor is deleted.
auto Result = Async(EAsyncExecution::Thread, [&]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}
});
An example of initializing the array in the main thread, then working on it inside the async task:
//Initialize the array and its structs (plus the float array inside the struct)
MyMainArray.Init(FMyDataStruct(2), 50000000);
//TFuture/Async task
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
//Call the main threads task completed function
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->MyTaskComplete();
}
});
});
Final thoughts:
Ultimately what I am asking is can anyone explain to me why from a C++ point of view the structs and their data would be removed from memory successfully when created/added from the main thread but then not removed from memory if created inside the async task/thread?
Update #1:
Here is a minimum reproducible example:
Create a new project in either Unreal Engine 4.23, 4.24 or 4.25.
Add a new C++ actor to the project and name it "MyActor".
Edit the source with the following:
MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
struct FMyDataStruct
{
FMyDataStruct()
{
//Default Constructor
}
FMyDataStruct(const FMyDataStruct& other)
: ArrayOfFloats(other.ArrayOfFloats)
{
//Copy constructor
}
FMyDataStruct(FMyDataStruct&& other)
{
//Move constructor
if (this != &other)
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
}
FMyDataStruct& operator=(const FMyDataStruct& other)
{
//Copy assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = other.ArrayOfFloats; //UE4 TArray deep copy
}
return *this;
}
FMyDataStruct& operator=(FMyDataStruct&& other)
{
//Move assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
return *this;
}
FMyDataStruct(int32 FloatCount)
{
//Custom constructor to initialize the float array
if (FloatCount > 0)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
}
~FMyDataStruct()
{
//Destructor
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
public:
TArray<float> ArrayOfFloats;
};
UCLASS()
class BASICPROJECT1_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:
virtual void Destroyed() override;
public:
bool IsEditorOnly() const override;
bool ShouldTickIfViewportsOnly() const override;
virtual void Tick(float DeltaTime) override;
void DoSomething();
void AsyncTaskComplete();
bool bShouldCount = true;
float TimeCounter = 0.f;
TArray<FMyDataStruct> MyMainArray;
};
MyActor.cpp
#include "MyActor.h"
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor::Tick(float DeltaTime)
{
if (!HasAnyFlags(RF_ClassDefaultObject)) //Check for not CDO. We only want to run in the instance
{
if (bShouldCount)
{
TimeCounter += DeltaTime;
if (TimeCounter >= 5.f)
{
bShouldCount = false;
DoSomething();
}
}
}
}
void AMyActor::Destroyed()
{
Super::Destroyed();
MyMainArray.Empty();
MyMainArray.Shrink();
UE_LOG(LogTemp, Warning, TEXT("Actor got Destroyed!"));
}
bool AMyActor::IsEditorOnly() const
{
return true;
}
bool AMyActor::ShouldTickIfViewportsOnly() const
{
return true;
}
void AMyActor::DoSomething()
{
//Change the code that is run:
//1 = Main thread only
//2 = Async only
//3 = Init on main thread and process in async task
//======================
int32 CODE_SAMPLE = 1;
UE_LOG(LogTemp, Warning, TEXT("Actor is running DoSomething()"));
TWeakObjectPtr<AMyActor> Self = this;
if (CODE_SAMPLE == 1)
{
//CODE 1: Run on main thread. This part DOES empty the RAM when run. BLOCKS the editor window.
//=========================================================================
MyMainArray.Empty();
MyMainArray.Shrink();
MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyMainArray.Emplace(MyDataStruct);
}
UE_LOG(LogTemp, Warning, TEXT("Main thread array fill is complete!"));
}
else if (CODE_SAMPLE == 2)
{
//CODE 2: Run on async task. This does NOT empty the RAM when run
//(4 bytes per float * 2 floats * 50,000,000 structs = 400Mb is left in system memory after the actor is deleted)
//=========================================================================
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
Self->MyMainArray.Empty();
Self->MyMainArray.Shrink();
Self->MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
Self->MyMainArray.Emplace(MyDataStruct);
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
else if (CODE_SAMPLE == 3)
{
//CODE 3: Initialize the array in the main thread and work on the data in the async task
//=========================================================================
MyMainArray.Init(FMyDataStruct(2), 50000000);
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
}
void AMyActor::AsyncTaskComplete()
{
UE_LOG(LogTemp, Warning, TEXT("Async task is complete!"));
}
Compile and run the project.
Drag the actor into the level editor window.
After 5 seconds the code will run and the RAM usage will increase to 1750Mb.
Select the actor in the outliner window and delete it.
The RAM usage will perform like this:
CODE 1: RAM is cleared out all the way to the starting RAM usage of 650Mb.
CODE 2: RAM is cleared down to 1000Mb and never returns to starting usage.
CODE 3: RAM is cleared out all the way to the starting RAM usage of 650Mb.
I thank you for your help.
Sorry, but I have to repeat the same question as I asked before "C++, Adding conditions in class vars".
I am using SDL2 here.
In obj.h: (excluding preprocessor commands)
class obj {
public:
SDL_Rect clip;
void addCollideWith( SDL_Rect rect );
void hasCollide();
void clearCollideWith();
private:
std::list<bool *> collideWith;
};
In obj.cpp: (excluding preprocessor commands)
void obj::addCollideWith( SDL_Rect rect )
{
collideWith.push_back(SDL_HasIntersection(obj.clip, rect));
}
void obj::hasCollide()
{
bool retval = true;
for (std::list<bool *>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval && **it;
}
return retval;
}
void clearCollideWith()
{
collideWith.clear();
}
Inside main function, I am saying that the object moves by one pixel and every time when it moves by one pixel, it checks for collision with other objects. I cleared the pointer thing '*' as I am not putting in variables as you can see: collideWith.push_back(SDL_HasIntersection(obj.clip, rect));. What I do is to make it move a pixel, clear collideWith and add collideWith condition again for updating whether it is true or false.
Now, whats the problem?
Its making the program really really slow! If I remove collideWith thing and then, starts the program, it gets a lot more smoother. Now, what I want, is to store the statement rather than true or false. std::list takes:
collideWith.pushBack(true /*OR*/ false);
But what I want is:
collideWith.pushBack(/*statement determining whether it is true or false*/ var1 > var2);
Please do complain if context is missing or the question is somehow, not understandable!
(NOTE: Context related to moving the object and declaring obj clip sub-vars is not mentioned as they are not a part of question.)
You could try to replace
std::list<bool *> collideWith;
with
std::list<SDL_Rect> collideWith;
in order to track of the rectangles that you want to considere.
The implementation could be :
void obj::addCollideWith( SDL_Rect rect )
{
collideWith.push_back(rect);
}
// to test if it collides with at least one rectangle
bool obj::hasCollide()
{
bool retval = false;
for (std::list<SDL_Rect>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval || SDL_HasIntersection(obj.clip, *it);
}
return retval;
}
// to test if it collides with all rectangles
/* bool obj::hasCollide()
{
bool retval = true;
for (std::list<SDL_Rect>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval && SDL_HasIntersection(obj.clip, *it);
}
return retval;
} */
I have a cursor that has its "position" determined by another part of the code. My intention is to have this cursor check through the next and previous object of a vector and check for a condition. If it's valid, the cursor takes this object's position.
Here's some sample code of my idea:
class A
{
bool valid;
public:
A(bool v) {valid=b;}
bool IsValid() {return valid;}
};
void CheckNearbyValidity()
{
/*if the object to the right is valid, update position to this object*/
if(exampleVector.at(cursor-1).IsValid())
{
/*do stuff*/
cursor = (cursor-1);
}
/*if the object to the right isnt valid, try the same thing to the left*/
else if(exampleVector.at(position+1).IsValid())
{
/*do stuff*/
cursor = (cursor+1);
}
/*leave if none are valid*/
}
The problem I encounter here is that if the cursor is at the start or end of the vector, checking the if conditions will cause it to throw an out of range exception.
My solution was to check if the new cursor position was valid before querying the vector:
void CheckNearbyValidity()
{
/*if the object to the right is valid, update position to this object*/
if(cursor-1 >= 0)
{
if(exampleVector.at(cursor).IsValid())
{
/*do stuff*/
cursor = (cursor-1);
}
}
/*new position makes the next condition always true and returns cursor to the same position*/
if(cursor-1 < exampleVector.size())
{
if(exampleVector.at(cursor+1).IsValid())
{
/*do stuff*/
cursor = (cursor+1);
}
}
/*leave if none are valid*/
}
The new problem was that since I could no longe use "else", both conditions would be valid and the cursor would remain where it started.
My workaround to this problem was to surround the function in a while loop, and break when necessary:
void CheckNearbyValidity()
{
while(true)
{
if(cursor-1 >= 0)
{
if(exampleVector.at(cursor-1).IsValid())
{
/*do stuff*/
position = (cursor-1);
break;
}
}
if(cursor-1 >= 0)
{
if(exampleVector.at(cursor+1).IsValid())
{
/*do stuff*/
position = (cursor+1);
break;
}
}
break;
}
}
My question is, is the "single" while loop approach a bad idea? Is there a better way to manipulate this cursor?
You should harness the power of &&:
if (cursor-1 >= 0 &&
exampleVector.at(cursor-1).IsValid())
{
/*do stuff*/
position = (cursor-1);
}
else if (cursor+1 < exampleVector.size() &&
exampleVector.at(cursor+1).IsValid())
{
/*do stuff*/
position = (cursor+1);
}
This allows you to connect the two statements together as an if-else as you had originally, only with the additional validation step checking cursor against the vector bounds.
The && performs short-circuit evaluation. If cursor-1 >= 0 evaluates to false, then the code skips evaluating exampleVector.at(cursor-1).IsValid() and jumps immediately to evaluating the else clause.
Likewise, in the else if clause, if cursor+1 < exampleVector.size() evaluates to false, the && short-circuits and the code skips evaluating exampleVector.at(cursor+1).IsValid(), again making it safe.
What could cause this?
Here's the stack trace:
#0 0x0645c0f5 in std::_Rb_tree_increment (__x=0x83ee5b0)
at ../../../../libstdc++-v3/src/tree.cc:69
#1 0x0805409a in std::_Rb_tree_iterator<std::pair<std::string const, Widget*> >::operator++ (
this=0xbffff144)
at /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/stl_tree.h:192
#2 0x08053d32 in Generic::StartLayout (this=0x8287d68) at Generic.cpp:195
#3 0x0804f6e1 in LCDControl::ConfigSetup (this=0xbffff26c) at LCDControl.cpp:91
#4 0x0804ed7c in LCDControl::Start (this=0xbffff26c, argc=1, argv=0xbffff404) at LCDControl.cpp:21
#5 0x08050964 in main (argc=1, argv=0xbffff404) at Main.cpp:11
And here's the code:
for(std::map<std::string,Widget *>::iterator w = widgets_.begin();
w != widgets_.end(); w++){
if( w->second->GetType() & WIDGET_TYPE_BAR) {
w->second->SetupChars();
}
w->second->Start();
}
Edit: This next problem is related, so I won't open a whole new question. I'll leave the answer acceptance like it is. I just need to know something. I have two iterators, one main and one within that main after a function call. They both relate to the same map. Well, the one inside gets all corrupted, and the main one's loop stops iterating.
Here's the code.
Here's StartLayout:
void Generic::StartLayout() {
Error("StartLayout: %s", key.c_str());
for(std::map<std::string,Widget *>::iterator w = widgets_.begin();
w != widgets_.end(); w++){
Error("Starting widget %s", w->first.c_str());
if( w->second->GetType() & WIDGET_TYPE_SPECIAL) {
w->second->SetupChars();
}
w->second->Start();
}
}
And here's SetupChars():
void WidgetGif::SetupChars() {
Error("SetupChars <%s> <%s>", name_.c_str(), widget_base_.c_str());
Error("Size of widgets: %d", visitor_->Widgets().size());
std::map<std::string, Widget *> widgets = visitor_->Widgets();
for(std::map<std::string, Widget *>::iterator ii=visitor_->Widgets().begin();
ii != visitor_->Widgets().end(); ii++) {
Error("<%s> Widget base %s == %s", ii->first.c_str(), ii->second->GetWidgetBase().c_str(), widget_base_.c_str());
if(ii->second->GetWidgetBase() == widget_base_ &&
((WidgetGif *)ii->second)->HasChars()) {
Error("Using chars from %s", ii->first.c_str());
for(unsigned int i = 0; i < rows_ * cols_; i++ ) {
if(i >= visitor_->GetLCDText()->CHARS) {
Error("1) GIF too large: %s, %d", name_.c_str(), visitor_->GetLCDText()->CHARS);
if(update_) delete update_;
update_ = new Property(visitor_, section_, "", new Json::Value("-1"));
return;
}
ch_[i] = ((WidgetGif *)widgets[ii->first])->GetChars()[i];
}
hasChars_ = true;
return;
}
}
// It goes on, but I snipped it here.
}
And this is what happens:
StartLayout: display_qt
Starting widget widget_gif_american_flag:layout_american_flag:0
SetupChars <widget_gif_american_flag:layout_american_flag:0> <layout_american_flag>
Size of widgets: 5
<widget_gif_american_flag:layout_american_flag:1> Widget base layout_american_flag == layout_american_flag
<widget_gif_american_flag:layout_american_flag:4> Widget base layout_american_flag == layout_american_flag
<(n
(n
��S> Widget base ГS == layout_american_flag
^C
Last edit: I figured it out. I just needed a copy of the original map for the new iterator.
There could be quite a few reasons for that. For one, it may be that GetType or SetupChars or Start do something that causes your map to change - which would invalidate the current iterator (note that using operator[] on the map, even just to read the value, is technically a mutating operation, and can cause a crash with iterator debugging enabled!). Alternatively, your map could be corrupted in memory by some code that executed before, e.g. because of a buffer overrun overwriting part of the map's tree.
You must not modify widgets_ in any of your methods GetType, SetupChars, or Start. This is most likely your problem.
If you must modify widgets_, then you will need to restart the iterator whenever such a change is made. To avoid duplicating your changes, you can use a simple marker dictionary outside the loop, or a marker member of the Widget class.