Memory changing between two functions calls
this is totally strange. I have some code in which I read some parameters from a file and I store them in two stl vectors. I have atoms and residues, and every atom keeps a pointer to his residue. Once finished reading, after declaring a variable, looks like the values in memory changed:
atoms[0].resid :0x96fc250 &(atoms[0].resid->ID) :0x96fc25c **(atoms[0].resid->ID) :1** atoms[1].resid :0x96fc250 &(atoms[1].resid->ID) :0x96fc25c **(atoms[1].resid->ID) :1** atoms[2].resid :0x96fc3ec &(atoms[2].resid->ID) :0x96fc3f8 (atoms[2].resid->ID) :2 atoms[3].resid :0x96fc3ec &(atoms[3].resid->ID) :0x96fc3f8 (atoms[3].resid->ID) :2 --------------------------------------- atoms[0].resid :0x96fc250 &(atoms[0].resid->ID) :0x96fc25c **(atoms[0].resid->ID) :891301941** atoms[1].resid :0x96fc250 &(atoms[1].resid->ID) :0x96fc25c **(atoms[1].resid->ID) :891301941** atoms[2].resid :0x96fc3ec &(atoms[2].resid->ID) :0x96fc3f8 (atoms[2].resid->ID) :2 atoms[3].resid :0x96fc3ec &(atoms[3].resid->ID) :0x96fc3f8 (atoms[3].resid->ID) :2
Here is the code. I don't really know what I did wrong
#define FT_GRO 1
using namespace std;
class residue{
public:
residue(){}
residue(const residue& r){atoms=r.atoms; ID=r.ID; name= r.name;}
residue(int n, string s) {name=s;ID=n;}
public:
vector<class atom*> atoms;
int ID;
string name;
atom& addAtom(atom& a) { atoms.push_back(&a); return a;}
};
class atom{
public:
atom(){}
atom(const atom& a){ID=a.ID,name=a.name,coord=a.coord,resid=a.resid ;}
atom(const int anum, const string aname,开发者_Go百科 const point3D& p, residue& res){coord=p; name=aname; resid=&res; ID=anum;}
~atom(){}
public:
point3D coord;
int ID;
string name;
double distance(point3D& p) {return coord.distance(p);}
double distance(atom& p) {return coord.distance(p.coord);}
class residue* resid;
};
int main(){
vector<atom> atoms;
vector<residue> residues;
double box1,box2,box3,x,y,z;
char l[256];
int nr,na;
string sr,sa;
int lastResNum = -1;
string lastResName("");
int nAtomsIn=4;
for(int i =0; i<nAtomsIn;i++){
cin.getline(l,255);
istringstream ssatm(l,ios::in);
ssatm >> setw(5) >> nr >> setw(5) >> sr >> setw(5) >> sa >> setw(5) >>na >> setw(8) >> x >>setw(8) >> y >>setw(8) >> z;
if (lastResNum!=nr || sr!=lastResName){
residues.push_back(residue(nr,sr));
}
point3D p(x,y,z);
atoms.push_back( atom(na,sa,p,residues.back()) );
residues.back().addAtom(atoms.back());
cout << "atoms["<<i<<"].resid :" << atoms[i].resid << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << &(atoms[i].resid->ID) << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << (atoms[i].resid->ID) << endl;
lastResNum=nr; lastResName=sr;
}
cout << "---------------------------------------"<<endl;
cin.getline(l,255);
istringstream ssbox(l);
ssbox >> setw(10) >> box1>>setw(10) >> box2>>setw(10) >> box3;
for(int i =0; i<atoms.size();i++){
cout << "atoms["<<i<<"].resid :" << atoms[i].resid << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << &(atoms[i].resid->ID) << endl;
cout << "&(atoms["<<i<<"].resid->ID) :" << (atoms[i].resid->ID) << endl;
}
return 0;
}
What you're seeing is perfectly normal behaviour -- when you add new elements to a vector, it may get resized, hence all the elements are copied to a new memory location.
If you need a guarantee that existing elements aren't moved in memory, use a different container such as list
or set
.
std::vector will move memory when it needs more space. It allocates a contiguous block of memory, and when that block fills up, it allocates a bigger block, copies all the elements from the old block to the new one, frees the old block, and moves on.
To prevent the behavior you are seeing, you can do any of a few things to improve your design patter:
1) Change your vectors in main() to store pointers instead of stack options. This way, the object will always be in the same place in memory. 2) Change your class declarations to allow deep copies by implementing a copy-constructor and assignment operator 3) Modify your class heirarchy to remove the circular dependency between your classes. You can do this by having a Residue class, an Atom class, and another class that maps the 2 to each other.
The simplest option will be #1. You'll just need to make sure you clean up memory properly.
Like casablanca said, whenever your vector expands, it change where the objects are in memory. If you really want to use vectors instead of some other container
1) you can reserve
a large piece of memory for your vector. If you have a guarantee that the number of these objects won't exceed a certain bound and you don't mind using up that much memory, then make your vector that large.
2) make them vectors of pointers. If you have a very modern compiler (gcc >= 4.4 for example), you may even have access to the new unique_ptr smart pointer class from C++0x, which lets you use smart pointers in stl containers. These great additions to the language.
精彩评论