-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