-1

我遇到了一个非常令人沮丧的指针问题。我以前发布在这里: TOUGH: Dealing with deeply nested pointers in C++C++中的奇怪指针问题

但是这篇文章太长了,是陈旧的,所以我选择重新发布更多的细节。

这里是我的头文件,它定义了我的类型:

#include <string> 
#include <vector> 
#include <sstream> 
#include <iostream> 

#define USE_3D_GEOM 
//#define USE_2D GEOM 

#define DEBUG 

#ifdef USE_3D_GEOM 
#define DIMENSIONS 3 
#elif USE_2D_GEOM 
#define DIMENSIONS 2 
#else 
#define DIMENSIONS 1 
#endif 

#ifndef _COMMON_H 
#define _COMMON_H 

template<class T> 
inline T from_string(const std::string& s) 
{ 
    std::istringstream stream (s); 
    T t; 
    stream >> t; 
    return t; 
}; 

template <class T> 
inline std::string to_string (const T& t) 
{ 
std::stringstream ss; 
ss << t; 
return ss.str(); 
} 

enum e_ensemble_kind 
{ 
    MICROCANONICAL, 
    CANONICAL, 
    NVT, 
    GRAND_CANONICAL, 
    NPT, 
    NVE 
}; 

enum e_potential_kind 
{ 
    HARD_SPHERE, 
    SQUARE_WELL, 
    LENNARD_JONES 
}; 

enum e_file_types 
{ 
    MC_SIMPLE, 
    NAMD, 
    GROMACS, 
    CHARMM 
}; 

#ifdef USE_3D_GEOM 
typedef struct s_coordinates t_coordinates; 
#endif 

#ifdef USE_2D_GEOM 
typedef struct s_coordinates t_coordinates; 
#endif 

typedef struct s_particle t_particle; 

typedef struct s_bond t_bond; 

typedef struct s_angle t_angle; 


typedef struct s_dihedral t_dihedral; 

typedef struct s_molecule t_molecule; 

typedef struct s_lj_param t_lj_param; 

typedef struct s_bond_param t_bond_param; 

typedef struct s_angle_param t_angle_param; 

typedef struct s_dih_param t_dih_param; 

typedef struct s_lookup_tab t_lookup_tab; 

#ifdef USE_3D_GEOM 
struct s_coordinates 
{ 
    double x; 
    double y; 
    double z; 

    s_coordinates& operator+(const s_coordinates &to_add) 
    { 
    x += to_add.x; 
    y += to_add.y; 
    z += to_add.z; 
    return *this; 
    } 
    s_coordinates& operator-(const s_coordinates &to_subtract) 
    { 
    x -= to_subtract.x; 
    y -= to_subtract.y; 
    z -= to_subtract.z; 
    return *this; 
    } 
    s_coordinates& operator=(const s_coordinates &to_assign) 
    { 
    x = to_assign.x; 
    y = to_assign.y; 
    z = to_assign.z; 
    return *this; 
    } 
    bool operator==(const s_coordinates &to_assign) 
    { 

    return x == to_assign.x && y == to_assign.y && z == to_assign.z; 
    } 
}; 
#endif 

#ifdef USE_2D_GEOM 
struct s_coordinates 
{ 
    double x; 
    double y; 

    s_coordinates& operator+(const s_coordinates &to_add) 
    { 
    x += to_add.x; 
    y += to_add.y; 
    return *this; 
    } 
    s_coordinates& operator-(const s_coordinates &to_subtract) 
    { 
    x -= to_subtract.x; 
    y -= to_subtract.y; 
    return *this; 
    } 
    s_coordinates& operator=(const s_coordinates &to_assign) 
    { 
    x = to_assign.x; 
    y = to_assign.y; 
    return *this; 
    } 
    bool operator==(const s_coordinates &to_assign) 
    { 

    return x == to_assign.x && y == to_assign.y; 
    } 
}; 
#endif 

typedef struct s_particle 
{ 
    t_coordinates position; 
    double charge; 
    double mass; 
    std::string name; 
    std::vector<t_lj_param>::iterator my_particle_kind_iter; 

    s_particle& operator=(const s_particle &to_assign) 
    { 
    position = to_assign.position; 
    charge = to_assign.charge; 
    mass = to_assign.mass; 
    name = to_assign.name; 
    my_particle_kind_iter = to_assign.my_particle_kind_iter; 
    return *this; 
    } 
} t_particle; 

struct s_bond 
{ 
    t_particle * particle_1; 
    t_particle * particle_2; 
    std::vector<t_bond_param>::iterator my_bond_kind_iter; 

    s_bond& operator=(const s_bond &to_assign) 
    { 
    particle_1 = to_assign.particle_1; 
    particle_2 = to_assign.particle_2; 
    my_bond_kind_iter = to_assign.my_bond_kind_iter; 
    return *this; 
    } 
}; 

struct s_angle 
{ 
    t_particle * particle_1; 
    t_particle * particle_2; 
    t_particle * particle_3; 
    std::vector<t_angle_param>::iterator my_angle_kind_iter; 

    s_angle& operator=(const s_angle &to_assign) 
    { 
    particle_1 = to_assign.particle_1; 
    particle_2 = to_assign.particle_2; 
    particle_3 = to_assign.particle_3; 
    my_angle_kind_iter = to_assign.my_angle_kind_iter; 
    return *this; 
    } 
}; 


struct s_dihedral 
{ 
    t_particle * particle_1; 
    t_particle * particle_2; 
    t_particle * particle_3; 
    t_particle * particle_4; 
    std::vector<t_dih_param>::iterator my_dih_kind_iter; 

    s_dihedral& operator=(const s_dihedral &to_assign) 
    { 
    particle_1 = to_assign.particle_1; 
    particle_2 = to_assign.particle_2; 
    particle_3 = to_assign.particle_3; 
    particle_4 = to_assign.particle_4; 
    my_dih_kind_iter = to_assign.my_dih_kind_iter; 
    return *this; 
    } 
}; 

struct s_molecule 
{ 
    std::string res_name; 
    std::vector<t_particle> my_particles; 
    std::vector<t_bond> my_bonds; 
    std::vector<t_angle> my_angles; 
    std::vector<t_dihedral> my_dihedrals; 

    s_molecule& operator=(const s_molecule &to_assign) 
    { 
    res_name = to_assign.res_name; 
    my_particles = to_assign.my_particles; 
    my_bonds = to_assign.my_bonds; 
    my_angles = to_assign.my_angles; 
    my_dihedrals = to_assign.my_dihedrals; 
    return *this; 
    } 
}; 

struct s_lj_param 
{ 
    double epsilon; 
    double sigma; 
    std::string atom_kind_name; 
}; 

struct s_bond_param 
{ 
    std::string atom_1; 
    std::string atom_2; 
    double bond_coeff; 
    double default_length; 
}; 

struct s_angle_param 
{ 
    std::string atom_1; 
    std::string atom_2; 
    std::string atom_3; 
    double angle_coeff; 
    double default_angle; 
}; 

struct s_dih_param 
{ 
    std::string atom_1; 
    std::string atom_2; 
    std::string atom_3; 
    std::string atom_4; 
    std::vector<double> dih_coeff; 
    std::vector<unsigned int> n; 
    std::vector<double> delta; 
}; 

struct s_lookup_tab { 
    std::string name; 
    int code; 
}; 

#endif /*_COMMON_H*/ 

这里是一个电话,我做出型t_molecule(见上文t_molecule的定义头)的变种增加分子阵列。

void Molecule_Manager_Main::add_molecule(const t_molecule new_molecule) 
{ 
    std::cout << "TYPE :" << new_molecule.res_name << std::endl; 
    std::cout << "3: BOND PARTICLE 1 : " 
     << new_molecule.my_bonds[new_molecule.my_bonds.size()-1].particle_1->name 
      << std::endl; 
    std::cout << "3: BOND PARTICLE 2 : " 
    << new_molecule.my_bonds[new_molecule.my_bonds.size()-1].particle_2->name 
      << std::endl; 
    std::cout << "3: BOND ITER CONST : " 
    << new_molecule.my_bonds[new_molecule.my_bonds.size()-1].my_bond_kind_iter->bond_coeff 
      << " " 
    << new_molecule.my_bonds[new_molecule.my_bonds.size()-1].my_bond_kind_iter->default_length 
      << std::endl; 
    my_molecules.push_back(new_molecule); 
    std::cout << "99: INDEX : " << my_molecules.size()-1 << std::endl; 
    std::cout << "TYPE :" << my_molecules[my_molecules.size()-1].res_name << std::endl; 
    std::cout << "4: BOND PARTICLE 1 : " 
      << my_molecules[my_molecules.size()-1].my_bonds[my_molecules[my_molecules.size()-1].my_bonds.size()-1].particle_1->name 
      << std::endl; 
    std::cout << "4: BOND PARTICLE 2 : " 
    << my_molecules[my_molecules.size()-1].my_bonds[my_molecules[my_molecules.size()-1].my_bonds.size()-1].particle_2->name 
      << std::endl; 
    std::cout << "4: BOND ITER CONST : " 
    << my_molecules[my_molecules.size()-1].my_bonds[my_molecules[my_molecules.size()-1].my_bonds.size()-1].my_bond_kind_iter->bond_coeff 
      << " " 
    << my_molecules[my_molecules.size()-1].my_bonds[my_molecules[my_molecules.size()-1].my_bonds.size()-1].my_bond_kind_iter->default_length 
      << std::endl; 
    add_performed = true; 
} 

这工作完美... resname字符串打印,债券矢量中的最后一个债券的信息打印。然后,一旦我添加了所有的分子。我把这称为:

t_molecule * Molecule_Manager_Main::get_molecule(unsigned int index) 
{ 
    std::cout << "TYPE :" << my_molecules[index].res_name << std::endl; 
    std::cout << "5: BOND PARTICLE 1 : " 
     << my_molecules[index].my_bonds[my_molecules[index].my_bonds.size()-1].particle_1->name 
      << std::endl; 
    std::cout << "5: BOND PARTICLE 2 : " 
    << my_molecules[index].my_bonds[my_molecules[index].my_bonds.size()-1].particle_2->name 
      << std::endl; 
    std::cout << "5: BOND ITER CONST : " 
    << my_molecules[index].my_bonds[my_molecules[index].my_bonds.size()-1].my_bond_kind_iter->bond_coeff 
      << " " 
    << my_molecules[index].my_bonds[my_molecules[index].my_bonds.size()-1].my_bond_kind_iter->default_length 
      << std::endl; 
    return &(my_molecules[index]); 
} 

这出现segfaults在债券线。

我可以从我的索引中添加步骤打印,我不是覆盖我推到向量(大小不断增长)的分子告诉..

换句话说似乎是发生如下: 阅读子向量(工程) - >在父向量中添加更多项目 - >重读子向量(seg-faults)

这些函数是将分子变量添加到向量中的唯一方法,而且在我目前的测试中,分子变量只添加一次而没有修改。

任何想法????先谢谢你!!

+6

学习使用调试器,检查您用于访问阵列的索引。 – peterchen 2010-06-28 22:30:49

+1

如果您简化了一下代码,我会更愿意帮忙。请拿出无关紧要的线路。 – 2010-06-28 22:36:29

+0

对于调试器建议。如果您正在使用调试器,通常会诊断出这类问题。如果您非常不幸,可能需要2分钟。 (如果是别人的代码,再增加一分钟。) – 2010-06-28 22:36:53

回答

1

只是读取您访问名为my_bond_kind_iter的变量。在向量中添加更多项目后,它将调整大小。这意味着(假设你没有C++ 0x rvalue-aware容器)子向量也将被复制,使所有现有的指针和引用无效。所以当你尝试访问这个现在完全无效的旧迭代器时,你好分段错误。这当然也会发生,如果你添加更多的孩子向量。

向量迭代器是不安全的,你不能保留它们并在以后访问它们,因为向量调整大小,这意味着移动内存,这发生在实施的突发事件。

+0

终于有了真正的答案!当我向父矢量添加更多项目时,我该如何解决这个问题?网上有一篇教程讨论这个问题吗? (这似乎是一个更复杂的问题...)会切换我的版本的gcc帮助? – 2010-06-28 22:42:30

+0

@Jason:不,这是一个基本的算法问题。你需要通过索引来存储位置,而不是指针或引用或迭代器。或者,您可以使用不调整大小的容器,如链接列表,映射或散列映射,这些映射不会使引用/指针无效。 – Puppy 2010-06-28 22:44:06

+0

噢,还有一件事......只是为了澄清债券iter是一个绑定参数向量('t_bond_param'),它们在添加单个分子之前都已就位......所以如果父代的迭代器仍然失效即使指向的子矢量保持不变,矢量也在变化? – 2010-06-28 22:45:52

0

在不同的对象中存储迭代器以访问某些向量中的元素。这些迭代器在底层向量被修改时会失效,例如通过添加新元素。解引用这样的迭代器是未定义的行为。

当您添加新分子并稍后使用这些迭代器导致分段错误时,可能会修改已存储迭代器的向量。

+0

是的,这是问题!根据DeadMG的建议,我已经转换到索引,我的程序现在像一个魅力工作!欢呼! – 2010-06-29 22:15:47

0

我会是你,我会严重重构这段代码。

大多数情况下,当我遇到像你这样的问题(并且它变得非常罕见)时,我会重构代码,直到我清楚地看到问题。在这里,可以清楚地避免太多的重复。使用typedefs,引用,常量来避免重复。

重构允许您重新组织代码和思想,简化问题,使问题变得明显。花时间做这件事,你会发现问题的根源。

这可能不在此代码中。

(约重构,我建议阅读本:http://sourcemaking.com/refactoring

+0

即时阅读您发送的指南,因为我的时间允许。谢谢!顺便说一句,问题解决了 - 当矢量调整大小后,矢量结构中的指针变得无效... – 2010-06-29 22:17:27

+0

一个常见的错误,我也经历过这个地狱^^; – Klaim 2010-06-29 22:23:34

0

我会建议,以避免下标运算符(。,P EX my_molecules [指数]),而字迹代码(而不是限制性的跟踪代码),更喜欢at()成员函数。

+0

这是如何工作的?我查看了我的O'Reily Pocket Reference C++,但没有看到“at”函数部分......显然,在Google的“at”函数中输入“等等”是一个失败的冒险行为......你有没有好的这方面的资源?提前致谢! – 2010-06-29 22:15:03

+0

http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4027 – tojas 2010-06-30 06:38:56