忽视 std::string 会毁掉你的乐趣¶
不知道包含你需要数据的结构的真实性质,会导致你写出一个只在某些时候有效、关键时刻却失效的机器人。设想,例如,你正试图弄清楚游戏如何存储生物数据。在你假设的搜索中,你发现游戏中所有生物都存储在一个结构数组中,看起来像清单 5-3。
struct creatureInfo {
int uniqueID;
char name[16];
int nameLength;
int healthPercent;
int xPosition;
int yPosition;
int modelID;
int creatureType;
};
清单 5-3:你可能如何解读内存中发现的生物数据
扫描内存中的生物数据后,假设你注意到每个结构的前 4 个字节对每个生物都是唯一的,所以你把这些字节称为 uniqueID,并假设它们构成一个 int 属性。进一步查看内存,你发现生物的名字紧跟在 uniqueID 之后,经过一番推理,你确定名字有 16 字节长。你在内存中看到的下一个值原来是 nameLength;一个以 null 结尾的字符串居然有关联长度,这有点奇怪,但你忽略了这一点,继续分析内存中的数据。经过进一步分析,你确定了其余值的用途,定义了清单 5-3 中所示的结构,并编写了一个自动攻击特定名称生物的机器人。
在狩猎 Dragon、Cyclops、Giant 和 Hound 等名字的生物数周、测试你的机器人之后,你决定是时候把机器人交给朋友了。首次使用时,你把所有人聚集起来,去击杀一个名叫 Super Bossman Supreme 的 Boss。整个团队把机器人设置为先攻击 Boss,当 Boss 超出范围时瞄准 Demon 或 Grim Reaper 等较弱的生物。
当你的团队到达 Boss 的地下城时……你们全军覆没。
这个场景哪里出了问题?你的游戏一定是用 std::string 存储生物名称,而不是简单的字符数组。creatureInfo 中的 name 和 nameLength 字段实际上是 std::string 字段的一部分,name 字符数组是 dataA 和 dataP 成员的联合。Super Bossman Supreme 超过 15 个字符,由于机器人不知道 std::string 的实现,它没有认出这个 Boss。相反,它重新瞄准召唤出来的 Demon 生物,实际上让你无法瞄准 Boss,而他慢慢耗尽你的生命值和补给。