在构造函数中设置数组意味着稍后会失败

Array setup in constructor means failure later on

本文关键字:失败 意味着 数组 构造函数 设置      更新时间:2023-10-16

我遇到了一个问题,我的代码在尝试使用列表的size()函数时出现了分段错误。根据stackoverflow的建议:-),我构造了一个最小的情况,其中段错误发生(在下面的inventory.size()调用中)。它是:

#include <list>
class Thing {};
class Player {
private:
  int xpCalcArray[99];
  std::list<Thing*> inventory;
public:
  Player();
  int addToInv(Thing& t); // return 1 on success, 0 on failure
};
Player::Player() {
  // set up XP calculation array
  for (int i=1; i<100; i++) {
    if (i<=10) {
      xpCalcArray[i] = i*100;
    }
    if (i>10 && i<=50) {
      xpCalcArray[i] = i*1000;
    }
    if (i>50 && i<=99) {
      xpCalcArray[i] = i*5000;
    }
  }
}
int Player::addToInv(Thing& t) {
  if (inventory.size() == 52) {
  return 0;
  } else {
      inventory.push_back(&t);
  }
  return 1;
}
int main(int argc, char *argv[]) {
  Thing t;
  Player pc;
  pc.addToInv(t);
  return 1;
}

我注意到当我在Player构造器中删除数组的设置时,它工作得很好,所以这看起来是问题所在。我做错了什么?

您正在越界访问您的数组,这导致未定义行为。数组

的有效索引范围
int xpCalcArray[99];

为0 ~ 98。您正在访问索引99:

if (i>50 && i<=99) {
  xpCalcArray[i] = i*5000;
}

外部循环应该是

for (int i=0; i<99; i++) { ... }

注意,我从0开始,尽管这是一个假设,您实际上想要访问第一个元素。

那么最终条件可以简化为

if (i>50) {
  xpCalcArray[i] = i*5000;
}

如果您打算使用大小为100的数组,那么您需要

int xpCalcArray[100];

您正在访问数组的边界之外。这样做会导致未定义的行为,因此对随后发生的任何事情都没有合理的解释。数组的大小是99,所以最后一个索引是98。然而,您的for循环上升到99。

让你的数组大小为100:

int xpCalcArray[100];

或将for条件更改为i < 99

您试图修改第2个→第100个元素(而不是第1个→第99个),从而覆盖了99个int s数组。

在你的例子中,这恰好覆盖了std::list<Thing*>中的一些内存(CC_6直接存在于数组—不总是,但显然今天对你来说),因此,当你试图使用列表时,当它的内部成员数据不再是它所认为的那样时,所有的地狱都爆发了。

您的xpCalcArray定义从0到98(即99个元素的大小)

你的循环从0到99,走100步。

最后一个循环,在位置99写入xpCalcArray,这个位置不存在。这(间接地)导致你的分割错误,如在轨道上的轻竞赛的答案所示。

那么,将xpCalcArray的大小增加1:

int xpCalcArray[100];