【问题标题】:Unexplained Behavior with std::vectorstd::vector 出现无法解释的行为
【发布时间】:2013-09-12 23:57:35
【问题描述】:

在逐步检查一些导致代码的奇怪分段错误时,我发现在将一个向量分配给另一个向量后,接收向量会任意损坏。以下是来自类的复制构造函数的代码 sn-p,该类具有数据成员 vector<Piece> *pieces,这是一个动态分配的数组,包含类型为 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
}

基本上在调试期间,我会进入pieces[s] 成员访问功能。在循环体中,很明显m_start 有一个有效地址,但是当它退出循环体并在getPiece 中调用pieces[s] 上的索引运算符时,m_start 为NULL。当m_start 有效时,在循环的最后一次迭代和getPiece 中,在与循环体中相同的索引运算符调用期间,m_start 为 NULL,没有对 pieces[s] 执行任何操作。对我滥用 std::vector 或 std::vector 中的错误的任何见解将不胜感激。

【问题讨论】:

  • std::vector&lt;Piece&gt; *pieces ??为什么不std::vector&lt;std::vector&lt;Piece&gt;&gt; pieces
  • vector不属于性病,属于std
  • 你忘了ClassName::getPiece吗?
  • 我对 std::vector 的误用或 std::vector 中的错误 ...很可能是前者;特别是使用动态分配的向量数组,而不是另一个向量来包含它们。呼应沃尔特的评论,使用std::vector&lt;std::vector&lt;Piece&gt;&gt; pieces;
  • 这段代码看起来很奇怪...... Uint8 属于 std::size_t 的位置,不必要的 reserve() 当复制将在下一行发生时

标签: c++ vector


【解决方案1】:

在我看来,您在此处存在访问冲突:

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

首先(正如 Petr 所指出的),它应该是 s&gt;=sides

第二,这里的s和调用者中的s不一样。所以pieces[s] 可能还没有被分配,是一个空向量。测试它使用

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

顺便说一句,如果你只是使用,这一切都可以避免

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

并复制了整个内容。

【讨论】:

  • 一点也不。我此时进入操作员呼叫,num-1 显然小于 size。在函数执行之前,m_start 已经为 NULL。
  • 我想就是这样。是的,似乎在第一个循环之后放置第二个循环遍历两侧确实可行。
  • 不完全是“避免”,但是是的,这似乎更好。我不记得为什么我之前决定反对它
猜你喜欢
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
相关资源
最近更新 更多