2010-12-03 8 views
7

esto es totalmente extraño. Tengo un código en el que leo algunos parámetros de un archivo y los almaceno en dos vectores stl. Tengo átomos y residuos, y cada átomo mantiene un puntero a su residuo. Una vez terminada la lectura, después de declarar una variable, parece que los valores en la memoria cambiaron:Cambio de memoria entre dos llamadas de funciones

 
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 

Aquí está el código. Realmente no sé lo que hice mal

#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, 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; 

} 

Respuesta

13

Lo que están viendo es perfectamente comportamiento normal - al agregar nuevos elementos a un vector, puede quedar cambiar de tamaño, por lo tanto, todos los elementos se copian en una nueva ubicación de memoria.

Si necesita una garantía de que los elementos existentes no se mueven en la memoria, use un contenedor diferente como list o set.

+3

Derecha, use 'list' en lugar de' vector' para evitar la copia al agregar elementos nuevos al contenedor. – chrisaycock

+0

@chrisaycock: Iba a agregar eso. :) – casablanca

+1

O asegúrate de que el vector no los mueva. Si se asegura de que un vector no desbordará su área actual (mediante el ajuste de tamaño, por ejemplo, reserva()), los objetos no se moverán. –

1

std :: vector moverá la memoria cuando necesite más espacio. Asigna un bloque contiguo de memoria, y cuando ese bloque se llena, asigna un bloque más grande, copia todos los elementos del bloque antiguo al nuevo, libera el bloque anterior y continúa.

Para evitar el comportamiento que está viendo, puede realizar cualquiera de algunas cosas para mejorar su golpeteo de diseño:

1) Cambiar los vectores en main() para almacenar punteros en lugar de opciones de pila. De esta manera, el objeto siempre estará en el mismo lugar en la memoria. 2) Cambie sus declaraciones de clase para permitir copias profundas mediante la implementación de un operador de asignación y constructor de copias 3) Modifique su jerarquía de clases para eliminar la dependencia circular entre sus clases. Puedes hacer esto teniendo una clase Residue, una clase Atom y otra clase que asigne los 2 entre sí.

La opción más simple será # 1. Solo deberá asegurarse de limpiar la memoria correctamente.

0

Como dijo casablanca, cada vez que su vector se expande, cambia donde están los objetos en la memoria. Si realmente desea utilizar vectores en lugar de otro contenedor

1) puede reserve una gran pieza de memoria para su vector. Si tienes una garantía de que el número de estos objetos no excederá un límite determinado y no te importa usar esa cantidad de memoria, entonces haz que tu vector sea tan grande.

2) los convierte en vectores de punteros. Si tiene un compilador muy moderno (gcc> = 4.4 por ejemplo), incluso puede tener acceso a la nueva clase de puntero inteligente unique_ptr de C++ 0x, que le permite usar punteros inteligentes en contenedores stl. Estas grandes adiciones al lenguaje.

Cuestiones relacionadas