std::vector push_back and size issues *FIXED*

Started by
9 comments, last by Fruny 19 years, 4 months ago
I have recently been doing some coding and come across a very, very wierd bug which is impossible for me to duplicate. For the sheer sake of making things easier to diagnose for everyone, I wrote up this pseudo code:

#include <iostream>
#include <vector>
using namespace std;

class BaseClass{
   public:
       int value;  
       BaseClass(){ value = 0; }
};

class MajorClass{
   public:
       int numBaseClasses;
       std::vector<BaseClass> BaseClasses;
       MajorClass(){ numBaseClasses = 0; BaseClasses.clear(); }
       ~MajorClass(){ BaseClasses.clear(); }    
       int addClass();
};

int MajorClass::addClass(void){
    cout << "Size of Major Class at top of add: " << BaseClasses.size() << endl;
    BaseClass temp;
    temp.value = ++numBaseClasses;
    BaseClasses.push_back(temp);
    cout << "Size of Major Class after adding " << numBaseClasses << " classes: " << BaseClasses.size() << endl;
    return 1;
}   

MajorClass mc;

int changeValue(BaseClass *bc, int value){
       bc->value = value;
       return 1;
}     

int main(){
   mc.addClass();
   cout << "Size of Major Class after returning from add: " << mc.BaseClasses.size() << endl;
   mc.addClass();    
   cout << "Size of Major Class after returning from add: " << mc.BaseClasses.size() << endl;
   
   cout << mc.BaseClasses[0].value << endl;
   cout << mc.BaseClasses[1].value << endl;
   
   changeValue(&mc.BaseClasses[0], 5);
   cout << mc.BaseClasses[0].value << endl;
   
   system("PAUSE");
   return 1;
}    



Essentially, you have a base class and a major class which contains a vector of base classes. Essentially, this is what I am doing in my code. The output of this is:

Size of Major Class at top of add: 0
Size of Major Class after adding 1 classes: 1
Size of Major Class after returning from add: 1
Size of Major Class at top of add: 1
Size of Major Class after adding 2 classes: 2
Size of Major Class after returning from add: 2
1
2
5


The issue is, however, (and for some reason, its not in this code when you compile it...) that within my equivalent "addClass()" function, everytime I push I get size "1" or size "2", as it should be. However, outside the class function, in my main method, I am getting size "1539705258" and "3079410516"...every single time. But once I get back into the class method, I get 1 and 2 again, despite the fact I call size() almost back to back. I litterally call it one way (BaseClasses.size()), return to my main function, and call it again (as mc.BaseClasses.size()) and get something different. Does anyone have any idea what is going on? I have tried to isolate what is going on, calling things both in and outside the function. My actual code always crashses on this line:

cout << "Script Name 2: " << vm.scripts[1].szName << endl;    


The line is basically the mc.BaseClasses[1].value equivalent line. Anyone have any ideas, or how to get more info on this? I have tried to gather as much as I could, but am at a complete loss. All the data in the base class loads correctly, and everything seems to be fine within the class method...but once I try to call it outside the class method, the program crashes (memory issue, I would assume). The output from my program I am getting is:

Size of Scripts before anything: 0
Size of scripts at top of add: 0
Size of scripts after push back: 1
Script name (in class method): thread1.vse
Size of Scripts after add (in main method): 1539705258
Size of scripts at top of add: 1
Size of scripts after push back: 2
Script name (in class method): thread2.vse
Size of Scripts after add (in main method): 3079410516
Script Name 1 (in main method): thread1.vse
Script Name 2 (in main method): 


It crashses when trying to access the name of the second script Thanks for taking the time to read this. -visage [Edited by - visage on November 28, 2004 6:05:35 PM]
Advertisement
My magic 8-balls says : "Reference or pointer to a local variable".

I don't understand why you decided to show us code that does not trigger the error. Is it some kind of augury technique where we are supposed to find your errors by examining the entrails of a sacrificial program (cyber-haruspicy?)

I've seen the word 'thread'. Are you protecting your containers from race conditions?
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Sorry. The code that does trigger the error is much, much longer. About ...3000 lines longer :D I was trying to recreate the error and simply cant...except it seems to continue to exist in my other code.

Ignore anything about threads. Its for my scripting language, and im trying to get several scripts running at once...hence why I call them thread1 and thread2. Has nothing to do with race conditions. A good thought though.


Below is the actual code:

/*  WITHIN MY MAIN METHOD*/voodoomachine vm;cout << "Size of Scripts before anything: " << vm.scripts.size() << endl;    r = vm.loadScript("thread1.vse");    cout << "Size of Scripts after add (in main method): " << vm.scripts.size() << endl;    if(r < 0){        cout << "Could not load script \"thread1.vse\"." << endl;    }      r = vm.loadScript("thread2.vse");    cout << "Size of Scripts after add (in main method): " << vm.scripts.size() << endl;    if(r < 0){        cout << "Could not load script \"thread2.vse\"." << endl;    }        cout << "Script Name 1: " << vm.scripts[0].szName << endl;    cout << "Script Name 2: " << vm.scripts[1].szName << endl;    



/*    LOADSCRIPT method*/int voodoomachine::loadScript(std::string filename){   FILE *fp;   voodooscript tempScript;   std::string tempChar;   int instrStreamSize;      cout << "Size of scripts at top of add: " << scripts.size() << endl;      fp = fopen(filename.c_str(), "rb");   if(fp == NULL){      return FILE_DOES_NOT_EXIST;       }             //the file is open   tempScript.szName = filename;   for(int i = 0; i < 5; i++){      tempChar += fgetc(fp);   }   tempChar += '\0';   if(strcmp(tempChar.c_str(), CURR_VER)) return INCORRECT_VERSION;   tempChar.clear();      fread(&tempScript.header.iStackSize, sizeof(int), 1, fp);   if(tempScript.header.iStackSize == 0) tempScript.header.iStackSize = 1024;   tempScript.stack = (Op*)malloc(sizeof(Op)*tempScript.header.iStackSize);   if(tempScript.stack == NULL)      return -1;   for(int i = 0; i < tempScript.header.iStackSize; i++){      tempScript.stack.iType = 0;      tempScript.stack.iIntLiteral = 0;   }       fread(&tempScript.header.iGlobalDataSize, sizeof(int), 1, fp);   fread(&tempScript.header.iIsMainFunction, sizeof(int), 1, fp);   fread(&tempScript.header.iMainFunctionIndex, sizeof(int), 1, fp);   fread(&tempScript.header.iPriority, sizeof(int), 1, fp);   fread(&tempScript.header.iIsConstruct, sizeof(int), 1, fp);   fread(&tempScript.header.iConstructIndex, sizeof(int), 1, fp);   fread(&tempScript.header.iIsDeconstruct, sizeof(int), 1, fp);   fread(&tempScript.header.iDeconstructIndex, sizeof(int), 1, fp);      fread(&tempScript.iNumLines, sizeof(int), 1, fp);      tempScript.loadOps(fp, tempScript.iNumLines);   cout << "Size of scripts after loadops: " << scripts.size() << endl;      int numFuncs;   fread(&numFuncs, sizeof(int), 1, fp);   for(int i = 0; i < numFuncs; i++){      tempChar.clear();      function temp;      int nameSize;      fread(&temp.iIndex, sizeof(int), 1, fp);      fread(&nameSize, sizeof(int), 1, fp);      for(int i = 0; i < nameSize; i++){         tempChar += fgetc(fp);      }          temp.szName = tempChar;      fread(&temp.iEntryPoint, sizeof(int), 1, fp);      fread(&temp.iParamCount, sizeof(int), 1, fp);      fread(&temp.iLocalDataSize, sizeof(int), 1, fp);      tempScript.funcTable.push_back(temp);   }         int numObjects;   fread(&numObjects, sizeof(int), 1, fp);   for(int i = 0; i < numObjects; i++){      tempChar.clear();      object temp;      int nameSize;      fread(&temp.iIndex, sizeof(int), 1, fp);      fread(&nameSize, sizeof(int), 1, fp);      for(int i = 0; i < nameSize; i++){         tempChar += fgetc(fp);      }          temp.szName = tempChar;      fread(&temp.iSize, sizeof(int), 1, fp);      fread(&temp.iStackIndex, sizeof(int), 1, fp);      fread(&temp.iFuncIndex, sizeof(int), 1, fp);      tempScript.objectTable.push_back(temp);   }         int numStrings;   fread(&numStrings, sizeof(int), 1, fp);   for(int i = 0; i < numStrings; i++){      tempChar.clear();      int nameSize;      fread(&nameSize, sizeof(int), 1, fp);      for(int i = 0; i < nameSize; i++){         tempChar += fgetc(fp);      }          tempScript.stringTable.push_back(tempChar);   }            int numLabels;   fread(&numLabels, sizeof(int), 1, fp);   for(int i = 0; i < numLabels; i++){      tempChar.clear();      label temp;      int nameSize;      fread(&temp.iIndex, sizeof(int), 1, fp);      fread(&nameSize, sizeof(int), 1, fp);      for(int i = 0; i < nameSize; i++){         tempChar += fgetc(fp);      }          temp.szName = tempChar;      fread(&temp.iTargetIndex, sizeof(int), 1, fp);      fread(&temp.iFuncIndex, sizeof(int), 1, fp);      tempScript.labelTable.push_back(temp);   }            tempScript.iScriptNum = scriptNum++;      if(fgetc(fp) != EOF)      return LAST_MINUTE_READ_ERROR;      fclose(fp);      if(tempScript.header.iIsMainFunction == 1){      //the current line should be the iEntry point of the function located at      //the iMainFunctionIndex           //PushFrame(&tempScript, tempScript.funcTable[tempScript.header.iMainFunctionIndex].iLocalDataSize);      tempScript.iCurLine = tempScript.funcTable[tempScript.header.iMainFunctionIndex].iEntryPoint;        tempScript.iIsDone = 0;   }       else{      tempScript.iIsDone = 1;   }          //push it onto our scripts   scripts.push_back(tempScript);   cout << "Size of scripts after pushback: " << scripts.size() << endl;   cout << "Script name (in class method): " << scripts[scriptNum-1].szName << endl;   return 1;}    


Thanks for looking!
Can you show me the class declaration? I'm especially interested in the variable that is located right before scripts in the structure.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Here you go!

class voodoomachine {    public:        voodoomachine(){ scriptNum = 0; currScript = 0; }        ~voodoomachine(){}        int scriptNum; //number of scripts		int currScript; //the current script we are processing        std::vector<voodooscript> scripts; //the scripts themselves         //prototypes        ...};


Thanks for looking!

Nope, I can't think of a solution... though I noticed that your 'size after loadOps' never appeared in the output.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Yeah, its because I removed it from the original post...it does actually appear in my output.

Everything prints...just comes up with some wacky stuff.
Quote:Original post by visage
Yeah, its because I removed it from the original post...it does actually appear in my output.

Everything prints...just comes up with some wacky stuff.


Well, add some more until you do find the point where the data structure goes bonkers. If it happens during the function returns, you'll have to trace it in the debugger...
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Thanks for the help Fruny. I just ended up making my vector a bunch of pointers instead of copies of the classes. I think it had something to do with my deconstructor...though honestly, I dont know. It works now...

Thanks again
Show us the copy constructor and destructor of voodooscript, or better yet the whole class if it's not too large. I doubt the problem is really solved yet, you just pushed it away for a while. Since voodooscript has dynamically allocated members, it'd better also have those two well implemented (well, assignment operator too but that isn't called here).

This topic is closed to new replies.

Advertisement