bathtub
bathtub

Reputation: 426

Unexplained Behavior with std::vector

In Stepping through some weird segmentation fault causing code, I found that after the assignment of one vector to another, the receiving vector arbitrarily corrupts. The following is a code snippet from a copy constructor of a class which has a data member vector<Piece> *pieces which is a dynamically allocated array containing vectors of type Piece.

ClassName::ClassName(const Class &other) // copy constructor of class
{
  ...
  for(SIDE_t s = 0; s < sides; s++)
  {
    pieces[s].reserve(other.pieces[s].size());
    pieces[s] = other.pieces[s];   //vector is completely valid here
    for(Uint8 p = 0; p < pieces[s].size(); p++)
    {
     //it continues validity throughout loop
      if(other.pieces[s][p].getCell() != NULL)
    pieces[s][p].setCell(cells + (other.pieces[s][p].getCell() - other.cells));

      if(pieces[s][p].getCell() == NULL)
        out.push_back(&pieces[s][p]);
    }
    if(other.flags[s] != NULL)
      flags[s] = getPiece(other.flags[s]->getValue(), other.flags[s]->getSide());
       // vector is invalid in scope of getPiece, which receives completely valid arguments
    else
      flags[s] = NULL;
  }
}

Piece * const ClassName::getPiece(const Uint8 num, const SIDE_t s) const 
{
    return (num>nPieces || s>sides || num == 0)? NULL:&pieces[s][num-1];
  // Right here during the member access function of pieces,
  // it is clear that the vector was corrupted some how
}

Essentially during debugging, I would step into pieces[s] member access function. In the loop body, it is evident that m_start has a valid address, however when it exits the loop body and calls the index operator on pieces[s] in getPiece, m_start is NULL. There are no operations performed on pieces[s] between the last iteration of the loop when m_start is valid, and in getPiece when during the same call of the index operator as in the loop body, m_start is NULL. Any insight on my misuse of std::vector or bugs in std::vector would be appreciated.

Upvotes: 1

Views: 125

Answers (1)

Walter
Walter

Reputation: 45414

It looks to me that you have an access violation here:

return (num>nPieces || s>sides || num == 0)? NULL:&pieces[s][num-1];

First (as pointed out by Petr), it should read s>=sides.

Second, s here is not the same as s in the caller. So pieces[s] may not have been assigned yet and is an empty vector. To test it use

return (num>nPieces || s>=sides || num == 0)? NULL : &(pieces[s].at(num-1));

Btw, all this would have been avoided had you simply used

std::vector<std::vector<Piece>>

and copied the whole thing.

Upvotes: 1

Related Questions