Вопрос

Я столкнулся с ОЧЕНЬ неприятной проблемой с указателем.Ранее я публиковал здесь:ЖЕСТКИЙ:Работа с глубоко вложенными указателями в 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]);
} 

Этот сегмент затрагивает строку облигаций.

По индексам, которые я печатаю на шаге добавления, я могу сказать, что я не перезаписываю молекулы, которые я помещаю в вектор (размер растет)..

Другими словами, кажется, что происходит следующее:Прочитать вложенный вектор (работает) -> добавить еще несколько элементов в родительский вектор -> перечитать вложенный вектор (ошибки сегмента)

Эти функции являются ЕДИНСТВЕННЫМ средством добавления переменных molecules к вектору, а переменные molecules добавляются только один раз и не изменяются посмертно в моем текущем тесте.

Есть какие-нибудь идеи????Заранее благодарю вас!!

Это было полезно?

Решение

Просто читая, что вы получите доступ к варианту, называемую my_bond_kind_iter. После того, как вы добавите еще несколько элементов в родительском векторе, он будет изменить размер. Это означает (предполагая, что у вас нет контейнеров C ++ 0x RValue-Aware-Aware Awares), что дочерний вектор также будет скопирован, недействительный все существующие указатели и ссылки на него. Поэтому, когда вы пытаетесь получить доступ к этому старуму итератору, который сейчас полностью недействителен, ошибка сегментации Hello. Эта воля, конечно, также произойдет, если вы добавите больше в дочерний вектор.

Векторные итераторы не безопасны, вы не можете сохранить их вокруг и получать доступ к ним позже, потому что векторы изменяют изменение изменений, что означает перемещение памяти, и это происходит при прихождении реализации.

Другие советы

В разных объектах вы храните итераторы для доступа к элементам в некоторых векторах. Эти итераторы недействительны, когда базовый вектор модифицирован, например, добавляя новые элементы. Дереференция такого итератора не определена поведение.

Вероятно, вы измените векторы, для которых вы добавляете итераторы, когда вы добавляете новые молекулы и используете эти итераторы позже, приводятся к неисправностям сегментации.

Я бы на вашем месте провел тщательный рефакторинг этого кода.

В большинстве случаев, когда я сталкиваюсь с проблемой, подобной вашей (а это становится очень редким явлением) Я выполняю рефакторинг кода до тех пор, пока четко не увижу проблему.Здесь слишком много повторений, которых явно можно избежать.Используйте typedefs, references, consts, чтобы избежать повторений.

Рефакторинг позволяет вам реорганизовать ваш код и ваши мысли, упростить, сделать проблемы очевидными.Потратьте на это время, и вы найдете источник проблемы.

Это может отсутствовать в этом коде.

(что касается рефакторинга, я рекомендую прочитать это : http://sourcemaking.com/refactoring )

Я порекомендую избежать индексов оператора (p. Ex. My_molecules [index]) во время записи кода трассировки (но не ограничивает код трассировки), предпочитаю на функцию элементов ().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top