游戏开发者联盟

引用 std vector 元素引发的bug

,

表象

今天修改地图生成代码的时候,遇到一个让人摸不着头脑的bug,

std::vector<Room> rooms_;
Room &curRoom = rooms_[0];

while() {
   int x = room.x + xxx;  // mark1
   int y = room.y + yyy;  // mark2
   rooms_.push_back(Room(x,y,width,height));  //mark3
}

然而,这段并不复杂的代码频繁出现内存访问错误,表面原因就是room指向的内容竟然频频为野对象,导致xy(mark1,mark2)的值无意义,从xy转成vector下标时,造成下标越界。什么原因造成的呢?

背后原因分析

首先,room指向了野对象,那么说明所指对象肯定失效了。
但是,vector并未销毁,其内部对象怎么会失效?
那么只能说是vector内部改变了对象的地址,什么情况下会改变对象地址呢?就是vector的内部空间占满后,还需要插入对象的时候;或者从vector中间插入元素的时候。本例中,就是mark3的位置。

解决方法

不要使用引用,直接使用下标 rooms_[aabbCcIndex]。
如果这个变量使用的特别多,也可以使用一个lambda,来简化这个引用,

auto room = [&]() -> Room& { return rooms_[roomIndex]; };
room().x = room().x + 3;

或者 定一个宏

#define room rooms_[roomIndex]
room.x = room.x + 3;
//不要忘记最后一步
#undef room 

后记

这种bug比较隐晦,如果出错几率不高的话,又难以发现。其次,只要使用stl容器,都有可能发生类似bug,切记切记。如果我们在容器中存储的是指针的话,那么出现这种错误的几率就会低很多。