std::vector overwriting final value, rather than growing? - c++

I'm having an issue where using vector.push_back(value) is overwriting the final value, rather than appending to the end. Why might this happen? I have a sample item in the vector, so it's size never hits zero. Below is the code..
void UpdateTable(vector<MyStruct> *Individuals, MyStruct entry)
{
MyStruct someEntry;
bool isNewEntry = true;
for (int i = 0; i < Individuals->size(); i++)
{
if (!(strcmp(Individuals->at(i).sourceAddress, entry.sourceAddress)))
{
isNewEntry = false;
//snip. some work done here.
}
}
if(isNewEntry)
{
Individuals->push_back(entry);
}
}
This let's my first "sample" value stay in, and will allow for just one more item in the vector. When 2 new entries are added, the second overwrites the first, so the size is never larger than 2.
edit: More code, since this is apparently not the issue?
void *TableManagement(void *arg)
{
//NDP table to store discovered devices.
//Filled with a row of sample data.
vector<MyStruct> discoveryTable;
MyStruct sample;
sample.sourceAddress = "Sample";
sample.lastSeen = -1;
sample.beaconReceived = 1;
discoveryTable.push_back(sample);
srand(time(NULL));
while(1)
{
int sleepTime = rand() % 3;
sleep(sleepTime);
MyStruct newDiscovery = ReceivedValue();
if (newDiscovery.lastSeen != -1000) //no new value from receivedValue()
{
UpdateTable(&discoveryTable, newDiscovery);
}
printTable(&discoveryTable);
}
return NULL;
}

I'm going to hazard a guess:
Suppose MyStruct is declared like
struct MyStruct
{
const char *sourceAddress;
// Other Gubbins ...
};
And that ReceivedValue does something like
MyStruct ReceivedValue()
{
static char nameBuffer[MAX_NAME_LEN];
// Do some work to get the value, put the name in the buffer
MyStruct s;
s.sourceAddress = nameBuffer;
// Fill out the rest of MyStruct
return s;
}
Now, every structure you push into your vector has sourceAddress pointing to the same global buffer, every time you call ReceivedValue it overwrites that buffer with the new string - so every entry in your vector ends up with the same string.
I can't be sure without seeing the rest of your code, but I can be sure that if you follow some of the good C++ style suggestions in the comments to your question this possiblity would go away.
Edit for clarification: there's no need to heap allocate your structures, simply declaring sourceAddress as a std::string would be sufficient to eliminate this possibility.

The scope for the items you are pushing into the database is expiring. They're being destructed when you leave the {} in which they were created - and as such the reference to them is no longer valid.
You need to change it from vector<MyStruct> to vector<MyStruct*> (preferably using safe pointers from Boost:: instead of pointers, but you get the idea).
You are creating the item within the (limited) scope and pushing it onto the vector (while the struct is copied, the strings in it are not!) it then reuses the same memory location (most likely if properly optimized) to store the next "new" struct and the one after that and so on and so forth.
Instead, within the limited scope create MyStruct *myObject = new MyStruct and assign its values, then push the pointer to the vector.
Remember to delete all values from the vector before clearing it/destroying it!!
Or, of course, you could use std::string/CString/whatever instead of a char array and avoid the issue entirely by having a safe-to-copy struct.

ComputerGuru's answer works however there in another alternative. You can create a copy constructor and overload operator= for MyStruct. In these operations, you need to copy the actual string into the new struct. In C++, structs are nothing more than classes with default public access instead of default private access. Another alternative is to use std::string instead of char* for the string value. C++ strings already have this behavior.
struct MyStruct {
std::string sourceAddress;
int lastSeen;
int beaconReceived;
};

Seems odd to me: Maybe there is something wrong with the //snip part of the code?
Try to log the size of the vector before and after the push_back call (either in the debugger or using cout) and also have a look at the isNewEntry variable.

Your code looks alright to me. Is it possible that you are not passing the right vector in? What I mean is that the behaviour you describe would appear if somehow your Individuals vector is being reset to its orginal 1-entry state before you tried to add the 3rd entry, then it would appear as if your 2nd entry was being overwritten.
Here is what I mean:
int test_table()
{
string SampleAddresses[] = {"Sample Address 1", "Sample Address 2"};
for (int i = 0; i < 2; i++)
{
// All this work to build the table *should* be done outside the loop; but we've accidentally put it inside
// So the 2nd time around we will destroy all the work we did the 1st time
vector<MyStruct> Individuals;
MyStruct Sample;
Sample.sourceAddress = "Sample Address 0";
Test.push_back(Sample);
// this is all we meant to have in the loop
MyStruct NewEntry;
NewEntry.sourceAddress = SampleAddresses[i];
UpdateTable(Individuals, NewEntry);
}
//Now the table has 2 entries - Sample Address 0 and Sample Address 2.
}
If this was all your code then the problem would be obvious. But it might be concealed in some other pieces of code.

Related

mechanism that make a string empty after std::move() it

I have some confusion about how a std::move() really empty something.
I write some code:
int main()
{
string str1("this is a string");
std::cout<<std::boolalpha<<str1.empty()<<std::endl;
string str2(std::move(str1));
cout<<"str1: "<<str1.empty()<<endl;
cout<<"str2: "<<str2.empty()<<endl;
}
The output is:
false
true //this mean the original string is emptied
false
Why is the original string emptied every time?
I have read some meterial about the move semantics,including the original proposal of it(this one), which said:
The difference between a copy and a move is that a copy leaves the source unchanged. A move on the other hand leaves the source in a state defined differently for each type. The state of the source may be unchanged, or it may be radically different. The only requirement is that the object remain in a self consistent state (all internal invariants are still intact). From a client code point of view, choosing move instead of copy means that you don't care what happens to the state of the source.
So,according to this words, the original content of the str1 above should be some kind of undefined. But why is that every time it have been move(), it is emptied? (Actually I have test this behavior on both std::string and std::vector but the result is the same.)
To learn more, I define my own string class to test, as bellow:
class mstring
{
private:
char *arr;
unsigned size;
public:
mstring():arr(nullptr),size(0){}
mstring(char *init):size(50)
{
arr = new char[size]();
strncpy(arr,init,size);
while(arr[size-1] != '\0') //simply copy
{
char *tmp = arr;
arr = new char[size+=50]();
strncpy(arr,tmp,50);
delete tmp;
strncpy(arr-50,init+(size-50),50);
}
}
bool empty(){ return size==0;}
}
Doing the same thing:
int main()
{
mstring str("a new string");
std::cout<<std::boolalpha<<str.empty()<<std::endl;
mstring anotherStr(std::move(str));
std::cout<<"Original: "<<str.empty()<<std::endl;
std::cout<<"Another: "<<anotherStr.empty()<<std::endl;
}
The output is:
false
Original: flase //mean that the original string is still there
Another: false
Even I add a move constructor like this:
mstring(mstring&& rvalRef)
{
*this = rvalRef;
}
The result is still the same.
My question is: why is the std::string get emptied but my self-defined isn't?
Because that's how the std::string move constructor is implemented. It takes ownership of the old string's contents (i.e. the dynamically-allocated char array), leaving the old string with nothing.
Your mstring class, on the other hand, doesn't actually implement move semantics. It has a move constructor, but all it does is copy the string using operator=. A better implementation would be:
mstring(mstring&& rvalRef): arr(rvalRef.arr), size(rvalRef.size)
{
rvalRef.arr = nullptr;
rvalRef.size = 0;
}
This transfers the contents to the new string and leaves the old one in the same state that the default constructor would have created it. This avoids the need to allocate another array and copy the old one into it; instead, the existing array just gets a new owner.
So,according to this words, the original content of the str1 above should be some kind of undefined.
There is absolutely nothing about what the state should be. The specification says what the state could be: anything defined enough that it can be destroyed or assigned new value.
Empty qualifies as anything, so the state can be empty.
It also makes most sense in this case. A string is, essentially, something like
class string {
char *_M_data;
size_t _M_size;
size_t _M_alloc;
public:
...
}
where the _M_data is allocated with new and must be deleted with delete (this is customizable with the allocator parameter, but the default allocator does just that).
Now if you don't care about the state of the source, the fastest thing that can be done is to assign the buffer to the destination and replace the buffer with nullptr in the source (so it does not get deleted twice). A string with no buffer is empty.

Multiple Objects pointing to same array

I am fairly new to using pointers in C++ but I will try and explain what I want to do.
I have a class object Rx (receiver), and in my program I will be using multiple receivers at the same time. Each receiver has a vector of data (observations), for simplicity I am just using a vector of doubles. I also have an array of bools that determine which observations to use and I would like each receiver (as a member variable) have a pointer to this array. For example the first element in the array of bools will say "true or false use the first observation you have receiver".
Also, further in my code I would also like to point to an array of objects, would I follow the same procedure?
int main()
{
// The elements in this array are set in the code before
bool use_observations[100];
// I have chosen 3 for an example but in my actual code I have a vector
// of receivers since the quantity varies
Rx receiver_1, receiver_2, receiver_3;
// I would like to set the pointer in each receiver to point
// to the array use_observations
receiver_1.SetPointer(use_observations);
receiver_2.SetPointer(use_observations);
receiver_3.SetPointer(use_observations);
} // end of main()
My receiver class declarations and definitions:
class Rx{
public:
Rx(); // Constructor
Rx(const Rx& in_Rx); // Copy constructor
~Rx(); // Destructor
void SetPointer(bool* in_Array); // Function to set pointer to use_observation
private:
std::vector<double> data;
bool* pointer_to_array[10];
}; // end of class Rx
void Rx::SetPointer(bool* in_Array)`{*pointer_to_array`= in_Array);
This is where I get the problems, either it doesnt assign correctly (get lots of nulls or not assigned) or I get an error on pointer_to_array saying expression must be a modifiable value
I haven't bothered showing the constructor, copy constructor and Destructor. I know normally in the destructor you should delete the pointer however Rx does not own the data in the array so I do not want to delete it.
Thanks for your help
EDIT** I have shown some code that I am using and what I get for results and I have modified SetPointer() to display some results
int main
{
bool use_observations [6] = {true, true, true, true, true, true};
Rx receiver_1;
receiver_1.SetPointer(use_observations);
}
void Rx::SetPointer(bool* in_Array)
{
*pointer_to_array = in_Array;
for(int i = 0; i < 6; i++)
{
if(*pointer_to_array[i] == true)
std::cout << "Good" << std::endl;
} // end of for loop
} // end of SetPointer()
When I debug and step over (*pointer_to_array = in_Array) I get the result
{true, and 0xCCCCCCCC for the rest of the elements} and then on the second iteration of the for loop it crashes saying "Access violation reading location 0xCCCCCCCC
SECOND EDIT **
Thank you everyone for your help. #PaulMcKenzie pointed out in his implementation (in the comments) in Rx that I should have bool* pointer_to_array not bool* pointer_to_array[6] and that solved the issue. As well I should be pointing to the start of the array buffer, not a pointer to the array.
The issue is that you want a pointer to the start of the array buffer, not a pointer to the array.
class Rx{
public:
void SetPointer(bool* in_Array);
bool* pointer_to_array;
};
void Rx::SetPointer(bool* in_Array) {pointer_to_array = in_Array);
Note the removal of the *.

Can't Save structure content

I have the next problem:
I created the structure:
struct Series : vector<Candle>
{
Security Sec;
int LookFor;
int TF;
int Corrector;
string ID;
int line;
Series(){};
Series (int _lookfor);
void Update();
};
Constructor:
Series::Series (int _lookfor)
{
LookFor=_lookfor;
for (int i = 1; i<=LookFor; i++)
{
Candle cantype = Candle(i);
push_back(cantype);
}
}
So, then we call this construcor it fills object by candle-values. LookFor - is a number of candles in the vector-series.
After initialization i want update this serie (if there is more new candle, i want delete last one and insert new on the begining of vector-serie)
void Series::Update()
{
if (size()==LookFor)
{
if (newer(cantype,c1))
{
Candle cantype = Candle(1);
Candle c1 = at(0);
pop_back();
emplace(begin(),cantype);
}
}
I need to initialize a vector of these series:
vector vec;
vec.push_back(Series(3));
And constructor does its job, everithing is fine.
But then i update them:
for (size_t x =0; x<=size()-1;x++) vec[x].Update();
I have a problem: it cann't save changes in vector. In Update method everithing is fine, it inserts needed candle in itself, but then method is ended - the state of vector (each element of vec) has no changes. In method we see changes, but after it vector become after constructor-like, the state still the same.
Tell me, please, what am I doing wrong?
As others already mentioned, do not derive from these containers (could cause nasty errors like missing dtor calls and memory leaks, no virtual destructor is present in these containers). Instead, add the vector as a member or leave it as is, if you do private inheritance.
You may use the iterator interface for such containers:
for(std::vector<Series>::iterator sIt = vec.begin();sIt != vec.end();++sIt) sIt->Update();
For your task, consider using a deque or a list as a circular buffer instead of the vector for the Candles. It would perform better for insertions and therefore allows you to use push_front() instead of emplace() or insert().
Alternatively, you could hold an index of the vector element just past the last element (which should be the first) and just assign the new candle, et voilĂ , you've got a dense circular buffer.
There are implementations of such circular buffers, for example the one of boost:
http://www.boost.org/doc/libs/1_52_0/libs/circular_buffer/doc/circular_buffer.html
Despite logic issues, which could prevent the modification in certain states, I can't see, why your code doesn't work at all, at least not when I went through the snippets you posted.

How to free memory of dynamic struct array

As someone who never dealt with freeing memory and so on, I got the task to create a dynamic array of struct and create functions to add or delete array elements. When deleting I have to free the memory which is no longer necessary.
when deleting the 2nd element of an array of the size of 3, I move the 3rd element to the 2nd position and then delete the last one. When deleting the last one, I always get an error... Is there anyone who can find an solution for me?
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend* friendList = new myFriend[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = *tempFriend;
friendList[1] = *tempFriend2;
friendList[2] = *tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete &(friendList[2]); //and delete 3rd element to free memory
}
Why did you create temporary variables? They're not even needed.
If you use std::vector and std::string, the problem you're facing will disappear automatically:
std::vector<myFriend> friendList(10);
friendList[0]->number=1;
friendList[0]->name = "ABC";
friendList[1]->number=2;
friendList[1]->name = "XYZ";
friendList[2]->number=3;
friendList[2]->name = "123";
To make it work, you should redefine your struct as:
struct myFriend {
int number;
std::string name;
std::vector<std::string> hobbys;
};
If you're asked to work with raw pointers, then you should be doing something like this:
struct Friend
{
int number;
char* name;
};
Friend * friends = new Friend[3];
friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");
//similarly for other : friends[1] and friends[2]
//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;
delete [] friends; //and finally this!
And if you do any of the following, it would be wrong, and would invoke undefined behavior:
delete friends[2]; //wrong
delete &(friends[2]); //wrong
It is impossible to delete a subset from array allocated by new []
myFriend* friendList = new myFriend[10];
You have a single whole array
+------------------------------------------------------------------+
| friendList[0] | friendList[1] | ..... | friendList[9] |
+------------------------------------------------------------------+
You can not delete &(friendList[2]).
You get from C++ whole array of 10 elements.
This array starts from friendList (or &(friendList[0])).
operator delete with pointer to the address returned by new (i.e. friendList) is valid
only.
Two things I noticed. (1) You are apparently supposed to "create functions to add or delete elements" but you haven't done that, you have only created one function. (2) You are making your work harder than it needs to be by using a struct that also needs to manage memory. I suggest you use a simpler struct.
Your assignment is, in effect, to make a simple 'vector' class, so I suggest that you do that. Start with a struct that is empty. If the teacher requires you to use the myFriend struct as written, you can add that in after you finish making your vector like functions. I'm going to assume that you aren't allowed to make a class yet because most instructors make the mistake of leaving that until last.
struct MyStruct {
int value; // start with just one value here. Dealing with pointers is more advanced.
};
MyStruct* array;
int size;
int capacity;
void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'
// I leave the functions for you to implement, it's your homework after all, but I give some clues below.
void addMyStruct(MyStruct& value) {
// First check that there is enough capacity in your array to hold the new value.
// If not, then make a bigger array, and copy all the contents of the old array to the new one.
// (The first time through, you will also have to create the array.)
// Next assign the new value to array[size]; and increment size
}
void removeMyStructAtPosition(int position) {
// If the position is at end (size - 1,) then simply decrement size.
// Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
// from position to the end of the array.
}
int main() {
// test your new class here.
// don't forget to delete or delete [] any memory that you newed.
}
The array size is fixed at 10, so you don't need to delete any elements from it. But you do need to delete the name and hobbys elements of friendList[1] (and before you overwrite it). There are two problems here:
You are setting friendList[0]->name = "ABC"; Here, "ABC" is a constant zero-terminated string somewhere in memory. You are not allowed to delete it. So you have to make a copy.
You want to delete hobby[i] whenever it was assigned. But in your code, you can't tell whether it was assigned. So you have to set every element to 0 in the constructor, so that you will later know which elements to delete.
The proper place to delete these elements is in myFriends's destructor.
It seems the point of the question is to manage a dynamic array. The main problem is that he is using an array of friendList. Use an array of pointers to friendList:
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend** friendList = new myFriend*[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = tempFriend;
friendList[1] = tempFriend2;
friendList[2] = tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete friendList[2]; //and delete 3rd element to free memory
}
But everybody else is right -- there are major issues around memory allocation for both 'hobbys' and for 'name' that you need to sort out separately.
To do your homework I'd suggest to learn much more about pointers, new/delete operators, new[]/delete[] operators (not to be confused with new/delete operators) and objects creation/copying/constructors/destructors. It is basic C++ features and your task is all about this.
To point some directions:
1) When you dynamically allocate the object like this
MyType* p = new MyType;
or
MyType* p = new MyType(constructor_parameters);
you get the pointer p to the created object (new allocates memory for a single object of type MyType and calls the constructor of that object).
After your work with that object is finished you have to call
delete p;
delete calls the destructor of the object and then frees memory. If you don't call delete your memory is leaked. If you call it more than once the behavior is undefined (likely heap corruption that may lead to program crash - sometimes at very strange moment).
2) When you dynamically allocate array like this
MyType* p = new MyType[n];
you get the pointer p to the array of n created object located sequentially in memory (new[] allocates single block of memory for n objects of type MyType and calls default constructors for every object).
You cannot change the number of elements in this dynamic array. You can only delete it.
After your work with that array is finished you have to call
delete[] p; // not "delete p;"
delete[] calls the destructor of every object in the array and then frees memory. If you don't call delete[] your memory is leaked. If you call it more than once the behavior is undefined (likely program crash). If you call delete instead of delete[] the behavior is undefined (likely destructor called only for the first object and then attempt to free memory block - but could be anything).
3) When you assign the struct/class then operator= is called. If you have no operator= explicitly defined for your struct/class then implicit operator= is generated (it performs assignment of every non-static member of your struct/class).

STL List copies a struct, but the copied values are offset by two memory addresses

I'm compiling using Code::Blocks on Windows 7 using the MinGW compiler (which I can only assume is the latest version; both Code::Blocks and MinGW were installed this past week). My issue crops up under a particular circumstance, and my attempts to write a simpler script that demonstrates the problem have failed (which implies that there is something wrong with my structure). Also, my apologies for how long this post is.
Currently, I'm rolling with one class, FXSDL, which will act as an SDL wrapper:
class FXSDL
{
public:
FXSDL();
virtual ~FXSDL();
int Initialize();
int Render();
FXID CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims);
int SetAnim(FXID hRefID, FXID hAnimID);
FXID hPlayer;
protected:
private:
list<FXSurface> m_lstFXObjects;
list<FXSurface>::iterator m_liFirst;
SDL_Surface* m_lpsfSDLScreen;
Uint32 m_tmOld;
Uint32 m_tmFrame;
};
The value type of my list is:
struct FXSurface
{
FXID hRefID;
int wpxTile;
int hpxTile;
int wpxTotal;
int hpxTotal;
int cntTiles;
map<int, vector<int> > htAnims; // All animations
map<int, vector<int> >::iterator vCurr; // Currently active animation
vector<int>::iterator fiCurr; // Currently active frame
SDL_Surface* lpsfSDL;
SDL_Rect* lprcTiles; // Predefined frame positions
string* fpImage;
};
I've implemented very simple initialize and render function. The CreateCharacter function takes a few parameters, the most important of which is htAnims, a map of integer vectors (idea being: I define numeric ids with easy-to-remember representations, such as FXA_IDLE or FXA_WALK, as the key, and the series of number values representing frames for the animation as a vector). This could be fairly easily implemented as a multidimensional integer array, but animations are variable in length and I want to be able to add new anims (or redefine existing ones) without having to recast an array.
The CreateCharacter function is simple. It creates a new FXSurface, populates it with the required data, and pushes the new FXSurface onto the list:
FXID FXSDL::CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims)
{
//list<FXSurface>::iterator lpsfTemp;
FXSurface lpsfTemp;
list<FXSurface>::iterator lpsfPos;
SDL_Rect* lprcCurr = NULL;
int cntTileW = 0;
int cntTileH = 0;
int cntCurr = 0;
// Start off by initializing our container struct
//lpsfTemp = new FXSurface();
lpsfTemp.lpsfSDL = IMG_Load(fpImage.c_str()); // Try to load the requested image
if(lpsfTemp.lpsfSDL != NULL) // If we didn't fail to
{
// Assign some variables for tracking
lpsfTemp.hRefID = hRefID;
lpsfTemp.fpImage = &fpImage;
lpsfTemp.wpxTotal = lpsfTemp.lpsfSDL->w;
lpsfTemp.hpxTotal = lpsfTemp.lpsfSDL->h;
// If a tile width was specified, use it
if(wpxTile != 0)
{
lpsfTemp.wpxTile = wpxTile;
lpsfTemp.hpxTile = hpxTile;
} // Otherwise, assume one tile
else
{
lpsfTemp.wpxTile = lpsfTemp.wpxTotal;
lpsfTemp.hpxTile = lpsfTemp.hpxTotal;
}
// Determine the tiles per row and column for later
cntTileW = lpsfTemp.wpxTotal / lpsfTemp.wpxTile;
cntTileH = lpsfTemp.hpxTotal / lpsfTemp.hpxTile;
// And the total number of tiles
lpsfTemp.cntTiles = cntTileW * cntTileH;
lpsfTemp.lprcTiles = new SDL_Rect[cntTileW*cntTileH];
// So we don't calculate this every time, determine each frame's coordinates and store them
for(int h = 0; h < cntTileH; h++)
{
for(int w = 0; w < cntTileW; w++)
{
cntCurr = (h*cntTileW)+w;
lprcCurr = new SDL_Rect;
lprcCurr->w = lpsfTemp.wpxTile;
lprcCurr->h = lpsfTemp.hpxTile;
lprcCurr->x = w*lpsfTemp.wpxTile;
lprcCurr->y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = *lprcCurr;
lprcCurr = NULL;
}
}
// Now acquire our list of animations and set the default
//lpsfTemp.htAnims = new map<int, vector<int> >(*htAnims);
lpsfTemp.htAnims = htAnims;
lpsfTemp.vCurr = lpsfTemp.htAnims.find(FXA_WALK_EAST);
lpsfTemp.fiCurr = lpsfTemp.vCurr->second.begin();
this->m_lstFXObjects.push_back(lpsfTemp);
}
else
{
hRefID = 0;
}
return hRefID;
}
It is precisely as the object is pushed that the error occurs. I've stepped through the code numerous times. Initially, I was only able to tell that my iterators were unable to dereference to the FXSurface object. After using watches to identify the exact memory address that the iterator and list objects pointed to, and dereferencing the address, I noticed the reason for my segfaults: all the values which I put into the original FXSurface were pushed down two memory blocks when the list object copied it!
My process for doing this is simple. I set up a breakpoint at the return statement for CreateCharacter, which gives me a view of lpsfTemp (the FXSurface I later add to the list) and m_lstFXObjects (the list I add it to). I scroll through the members of m_lstFXObjects, which brings me to _M_node, which contains the memory address of the only object I have added so far. I add a watch to this address in the form of (FXSurface)-hex address here-
First, find the address:
(There should be a picture here showing the highlighted _M_node attribute containing the list item's address, but I can't post pictures, and I can only post one URL. The second one is by far more important. It's located at http://www.fauxsoup.net/so/address.jpg)
Next, we cast and deference the address. This image shows both lpsfTemp and the copy in m_lstFXObjects; notice the discrepancy?
http://www.fauxsoup.net/so/dereferenced.jpg - See? All the values are in the correct order, just offset by two listings
I had initially been storing fpImages as a char*, so I thought that may have been throwing things off, but now it's just a pointer and the problem persists. Perhaps this is due to the map<int, vector<int> > I store?
FXSDL has a destructor, but no copy constructor and no assignment operator. Yo you're using naked pointers, but violate the Rule of Three.
I'm not going to look any further.
Use smart pointers to manage resources. Do not put a naked resource into a type, except when that type's only intention is to manage this one resource. From another answer given yesterday:
As a rule of thumb: If you have to manually manage resources, wrap each into its own object.
At a glance, I'd say you're double-deleting lpsfSDL and/or lprcTiles. When you have raw pointers in your structure, you need to follow the rule-of-three (implement copy constructor, assignment operator, and destructor) to properly manage the memory.
These lines look wrong to me:
lprcCurr = new SDL_Rect;
lprcCurr->w = lpsfTemp.wpxTile;
lprcCurr->h = lpsfTemp.hpxTile;
lprcCurr->x = w*lpsfTemp.wpxTile;
lprcCurr->y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = *lprcCurr;
lprcCurr = NULL;
lpsfTemp.lprcTiles is a SDL_Rect*. lprcTemp.lprcTiles[cntCurr] is a SDL_Rect. You should be writing this, IMHO:
SDL_Rect tmpRect;
tmpRect.w = lpsfTemp.wpxTile;
tmpRect.h = lpsfTemp.hpxTile;
tmpRect.x = w*lpsfTemp.wpxTile;
tmpRect.y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = tmpRect;
Dump the lprcCurr entirely.
Now this code:
lpsfTemp.vCurr = lpsfTemp.htAnims.find(FXA_WALK_EAST);
lpsfTemp.fiCurr = lpsfTemp.vCurr->second.begin();
This is bad. These iterators are invalid as soon as the push_back completes. That push_back is making a copy of lpsfTemp. The map and vector members are going to copy themselves and those iterators will copy themselves but they will be pointing to lpsfTemp's members which are going to be destroyed as soon as CreateCharacter exits.
One way to fix that would be to push_back a FXSurface object at the beginning, use back() to get its reference and operate on that instead of lpsfTemp. Then the iterators would stay consistent and they should stay consistent since you are using a list which does not copy its objects around. If you were using a vector or deque or anything other than a list you would need to manage all those pointers and iterators in the copy constructor and assignment operator.
Another thing: Double and triple check your array bounds when you access that lprcTiles array. Any mistake there and you could be scribbling over who knows what.
I don't know if any of that will help you.