C ++の奇妙なポインターの問題
-
01-10-2019 - |
質問
私は非常にイライラするポインターの問題に遭遇しています。私は以前ここに投稿しました:タフ: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のvar(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]);
}
これは、ボンドライン上のセグフォールトです。
ADDステップで印刷するインデックスから、ベクトルに押し込んでいる分子を上書きしていないことがわかります(サイズは成長しています)。
言い換えれば、起こっているように見えることは次のとおりです。sub-vector(works) - >親ベクトルにさらにいくつかのアイテムを追加する - > REREADサブベクトル(セグフォールト)
これらの関数は、分子VARがベクターに追加される唯一の手段であり、分子VARは1回しか追加されず、現在のテストでは死後に修正されていません。
何か案は????前もって感謝します!!
解決
my_bond_kind_iterと呼ばれるバレイブルにアクセスすることを読んでください。親ベクトルにさらにアイテムを追加すると、サイズが変更されます。これは、子ベクターもコピーされ、既存のすべてのポインターと参照を無効にすることを意味する(C ++ 0x RValue-Awareコンテナを持っていないと仮定する)ことを意味します。したがって、この古いイテレーターにアクセスしようとすると、今では完全に無効になっています。こんにちはセグメンテーションの障害。もちろん、これは子供のベクターにさらに追加する場合にも発生します。
ベクトルイテレータは安全ではありません。ベクターがサイズを変更してメモリを移動することを意味するため、後でそれらを保持してアクセスすることはできません。これは実装の気まぐれで発生します。
他のヒント
さまざまなオブジェクトでは、いくつかのベクトルの要素にアクセスするために反復器を保存します。これらの反復因子は、たとえば新しい要素を追加することにより、基礎となるベクトルが変更されると無効になります。そのようなイテレーターの棄権は未定義の動作です。
おそらく、新しい分子を追加したときにイテレーターを保存したベクトルを変更し、後でこれらのイテレーターを使用してセグメンテーション障害につながります。
私はあなたになります、私はこのコードを大幅にリファクタリングします。
ほとんどの場合、私があなたのような問題を抱えているとき(そしてそれは非常にまれになっています)、私は明らかに問題を見るまでコードをリファクタリングします。ここでは、明らかに回避できる繰り返しが多すぎます。 typedefs、参照、constsを使用して、繰り返しを避けます。
リファクタリングにより、コードと思考を再編成し、簡素化し、問題を明らかにします。これを行うには時間がかかると、問題の原因が見つかります。
それはこのコードから外れている可能性があります。
(リファクタリングについては、これを読むことをお勧めします。 http://sourcemaking.com/refactoring )
Traceコードを作成しながら(ただし、トレースコードに制限されていない)、()メンバー関数を優先しながら、添え字オペレーター(p。ex。my_molecules[index])を避けることをお勧めします。