0

I have been dealing with a weird bug in my C++ code for over a day now.

I execute the polyline_analisis() function, inputting empty nodevector and edgevector like in the code below. The goal of the function is to create a std::vector from the previously computed polylines (lists of points):

polyline_t *it = q;
// std::vector<std::tuple<int, int, double, double, edge>> edgevector;
std::vector<edge> edgevector;
std::vector<node> nodevector;
node *inp_node;
node *out_node;
polyline_analysis(q, nodevector, edgevector, inp_node, out_node, R_combine, diameter, c_size, x_input, y_input, x_output, y_output);
    
//Store the vector for debugging
std::ofstream file;
file.open("Intermidiate_outputs/Edgevector.csv");
file << "Node1, Node2, Length, Diameter\n";
for (auto i : edgevector)
{
    //std::cout<<i.n_head->ind << ", " << i.n_tail->ind << ", " << i.length << ", "<<i.d <<"\n";
    file << i.n_head->ind << ", " << i.n_tail->ind << ", " << i.length << ", "<<i.d <<"\n";
}
file.close();

After running the code, however, I find out that there is a memory issue in the first two elements of edgevector, and more specifically their nodes that contain the node with index 0.

I output the contents of the vector into a .csv:

Node 1 Node 2
1432444944 1
2 1432444944
3 4
5 4
... ...

All values omitted in the table are also correct for the given edge.

typedef struct node
  {
    point_t *point;
    int ind;
    bool active;
    int x;
    int y;
    double pressure;
  } node;

  typedef struct edge
  {
    polyline_t *polyline;
    node *n_head;
    node *n_tail;
    bool active;
    double length;
    double d;
    double res;
  } edge;

//Unimportant code ...

void polyline_analysis(polyline_t *q, std::vector<node> &nodevector, std::vector< edge> &edgevector, node*& inp_node, node *&out_node, int R, double diameter, double c_size, int x_input, int y_input, int x_output, int y_output)
  {
    int counter = 0;
    counter=0;
    polyline_t *it = q;
    double min_inp_dist = std::pow(W, 2);
    double min_out_dist = std::pow(W, 2);
    bool in_radius;
    double length = 0;
    int test_count=0;
    int node_map[W][H]={};
    for(int m=0;m<W;++m)
    {
      for(int n=0;n<H;++n)
      {
        node_map[m][n]=-1;
      }
    }
    while (it)
    {
      point_t *jt = it->head;
      point_t *jtt = it->tail;
      point_t *jt2 = jt->next;

      // Add polyline head coordinates to vector nodecord
      std::pair<int, int> hcord(jt->x, jt->y);
      int hind = 0;
      in_radius = false;
      if (node_map[hcord.first][hcord.second]==-1)
      {
        for (int k = -R; k <= R; ++k)
        {
          if (hcord.first + k < W && hcord.first + k >= 0)
          {
            for (int q = -R; q <= R; ++q)
            {
              if (std::sqrt(std::pow(k, 2) + std::pow(q, 2)) <= R && hcord.second + q < H && hcord.second + q >= 0 && node_map[hcord.first + k][hcord.second + q]!=-1)
              {
                it->head->x = hcord.first + k;
                it->head->y = hcord.second + q;
                hind = node_map[hcord.first + k][hcord.second + q];
                in_radius = true;
                break;
              }
            }
          }
          if (in_radius)
            break;
        }
        if (!in_radius)
        {
          if(nodevector.empty())
            hind=0;
          else hind = nodevector.size();
          ++test_count;
          node_map[hcord.first][hcord.second]=hind;
          node temp = {
              it->head,
              hind,
              true,
              it->head->x,
              it->head->y,
              -1.0};
          nodevector.push_back(temp);
          if (std::pow(temp.x - x_input, 2) + std::pow(temp.y- y_input, 2) < min_inp_dist)
          {
            node *inp_ref=&nodevector[hind];
            inp_node = inp_ref;
            min_inp_dist = std::pow(temp.x - x_input, 2) + std::pow(temp.y - y_input, 2);
          }
          if (std::pow(hcord.first - x_output, 2) + std::pow(hcord.second - y_output, 2) < min_out_dist)
          {
            node *out_ref=&nodevector[hind];
            out_node = out_ref;
            min_out_dist = std::pow(hcord.first - x_output, 2) + std::pow(hcord.second - y_output, 2);
          }
        }
      }
      else hind=node_map[hcord.first][hcord.second];

      // Add polyline tail coordinates to vector nodecord
      std::pair<int, int> tcord(jtt->x, jtt->y);
      int tind = 0;
      in_radius = false;
      if (node_map[tcord.first][tcord.second]==-1)
      {
        for (int k = -R; k <= R; ++k)
        {
          if (tcord.first + k < W && tcord.first + k >= 0)
          {
            for (int q = -R; q <= R; ++q)
            {
              if (std::sqrt(std::pow(k, 2) + std::pow(q, 2)) <= R && tcord.second + q < H && tcord.second + q >= 0 && node_map[tcord.first + k][tcord.second + q]!=-1)
              {
                it->tail->x = tcord.first + k;
                it->tail->y = tcord.second + q;
                tind = node_map[tcord.first + k][tcord.second + q];
                in_radius = true;
                break;
              }
            }
          }
          if (in_radius)
            break;
        }
        if (!in_radius)
        {
          if(nodevector.empty())
           tind=0;
          else tind=nodevector.size();
          //std::cout<<"tind:"<<tind<<std::endl;
          node_map[tcord.first][tcord.second] = tind;
          node temp2 = {
              it->tail,
              tind,
              true,
              it->tail->x,
              it->tail->y,
              -1.0};
          nodevector.push_back(temp2);
          if (nodevector.size()-1!=tind) std::cout<<"Problem is in t "<<tind<<std::endl;
          
          if (std::pow(tcord.first - x_input, 2) + std::pow(tcord.second - y_input, 2) < min_inp_dist)
          {
            node *inp_ref=&nodevector[tind];
            inp_node = inp_ref;
            min_inp_dist = std::pow(tcord.first - x_input, 2) + std::pow(tcord.second - y_input, 2);
          }
          if (std::pow(tcord.first - x_output, 2) + std::pow(tcord.second - y_output, 2) < min_out_dist)
          {
            node *out_ref=&nodevector[tind];
            out_node = out_ref;
            min_out_dist = std::pow(tcord.first - x_output, 2) + std::pow(tcord.second - y_output, 2);
          }
        }
      }
      else tind= node_map[tcord.first][tcord.second];

      // Calculate poliline length
      int n = 0;
      double d_sum = 0;
      while (jt2)
      {
        length += std::sqrt(std::pow(jt2->x - jt->x, 2) + std::pow(jt2->y - jt->y, 2));
        d_sum += dt[jt->y * W + jt->x] * 2 - 1;
        n++;
        jt = jt->next;
        jt2 = jt2->next;
      }
      // Construct Edgevector contains index of tail  index of head, length and diameter
      double d = d_sum / n;
      std::cout<<"Head index hind "<<hind<<" from vector "<<nodevector[hind].ind<<" Tail index hind" <<tind<<" from vetor "<<nodevector[tind].ind<<std::endl;


      edge current = {
          it,                                                  // Polyline
          &nodevector[hind],                                   // headnode
          &nodevector[tind],                                   // tailnode
          true,                                                // Is active
          length,                                              // length
          d,                                                   // diameter
          Edge_Resistance(length, (double)(d_sum / n), c_size) // Edge resistance
      };
      edgevector.emplace_back(current);

      // Counters
      counter++;
      length = 0;
      it = it->next;
    }
  }

From debugging, I know that the error occurs during the iterations of the while(it) loop. On the iteration that each of the problematic edges are defined, they look completely okay, however once the code progresses to the next iteration, I start getting the non-initialized-like node values.

For the first iteration:

Node 1 Node 2
0 1

For the second iteration:

Node 1 Node 2
1432444944 1
2 0

For the third iteration:

Node 1 Node 2
1432444944 1
2 1432444944
3 4

A weird thing that I found is that, at the end of edgevector, there is one last edge connected to the 0 node:

Node 1 Node 2
1432444944 1
2 1432444944
3 4
... ...
51 0

The problem probably has to do with the index variable itself, as all other properties of the problematic nodes seem correct.

Does anyone have any idea what the cause of the problem could be?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 10
    Adding elements to the vector may invalidate all pointers and iterators into it, when the vector needs to reallocate. Keep indexes, not pointers, at least for as long as the vector is still being resized. – Igor Tandetnik May 18 '23 at 23:13
  • 1
    Working with raw pointers directly means your program may become fragile. Either don't let the vector reallocate its buffer or use a different approach. – digito_evo May 18 '23 at 23:27
  • Please edit your post to fix the bad markdown formatting (add blank lines before your tables). – Paul Dempsey May 18 '23 at 23:38
  • 1
    Good sources of documentation indicate how operations affect the validity of iterators, references etc. If you don't know the rules, then **you have to read the documentation before writing code**. – Phil1970 May 18 '23 at 23:47
  • 2
    When pushing an item into a `vector`, if its new `size` would exceed its current `capacity` then it has to reallocate its internal array, which invalidates any existing pointers/iterators to its elements. If you know beforehand how many items you are going to store in the `vector`, you can `reserve()` its capacity up front to avoid subsequent inserts from invalidating those pointers/iterators. – Remy Lebeau May 19 '23 at 00:14
  • 1
    @IgorTandetnik: Or, if you know an upper bound on the size of the `vector`, you can pre-`reserve` that amount of space to avoid the need for reallocation. – ShadowRanger May 19 '23 at 00:16

0 Answers0