4.5 理解向量的性能
如同所有STL容器一样,向量为程序员提供了巧妙的使用信息的方法。但是这种程度的巧妙可能带来性能上的代价。如果说有某一件事情困扰着游戏程序员,那就是性能。但是不必担心,向量和其他STL容器的效率极高。实际上,它们已经用于已发布的PC游戏和控制台游戏。然而,这些容器有其优势和劣势。游戏程序员需要理解各种容器类型的性能特性,以便为任务选择合适的容器。
4.5.1 向量的增长
尽管向量可以根据需要动态增长,但是每个向量都有特定的大小。当为向量添加新元素使其大于当前大小时,计算机重新分配内存,而且甚至有可能将向量的全部元素复制到新占用的内存块。这可能导致性能损失。
关于程序的性能,要记住的最重要的一点是并不一定必须担心内存重新分配的问题。例如,向量内存的重新分配可能并不是发生在程序的性能关键部分。在这种情况下,可以放心地忽略内存重新分配带来的性能损失。同样,如果向量较小,重新分配的代价也可能微不足道,因此还是可以放心地将其忽略。然而,如果需要对内存分配的时机有更加精确的控制,就要考虑性能了。
1. 使用capacity()成员函数
vector的成员函数capacity()返回向量的容量,即在程序必须为其重新分配更多内存之前,向量所能容纳的元素数目。向量的容量和向量的大小(向量当前容纳的元素的数目)不是同一概念。下面的代码可以帮助理解这一点:
- cout << "Creating a 10 element vector to hold scores.\n";
- vector<int> scores(10, 0); //initialize all 10 elements to 0
- cout << "Vector size is :" << scores.size() << endl;
- cout << "Vector capacity is:" << scores.capacity() << endl;
- cout << "Adding a score.\n";
- scores.push_back(0); //memory is reallocated to accommodate growth
- cout << "Vector size is :" << scores.size() << endl;
- cout << "Vector capacity is:" << scores.capacity() << endl;
在声明和初始化向量之后,这段代码报告向量的大小和容量都是10。然而,在添加一个元素之后,代码报告向量的大小是11,而容量是20。这是因为程序每次为向量重新分配额外的内存时,其容量都会增大一倍。在本例中,当添加新的分数后,程序重新分配内存,向量的容量从10倍增到20倍。
2. 使用reserve()成员函数
reserve()成员函数将向量的容量扩充至给定实参的大小。reserve()允许程序员控制重新分配额外内存的时机,如下例所示:
- cout << "Creating a list of scores.\n";
- vector<int> scores(10, 0); //initialize all 10 elements to 0
- cout << "Vector size is :" << scores.size() << endl;
- cout << "Vector capacity is:" << scores.capacity() << endl;
- cout << "Reserving more memory.\n";
- scores.reserve(20); //reserve memory for 10 additional elements
- cout << "Vector size is :" << scores.size() << endl;
- cout << "Vector capacity is:" << scores.capacity() << endl;
就在声明和初始化向量之后,这段代码报告其大小和容量都是10。然而,在预留了10个额外元素的内存后,代码报告其大小仍然为10,而容量为20。
使用reserve()将向量的容量维持在足够满足需要,这样可以将内存的重新分配推迟到某个选定时刻发生。
提示
初级游戏程序员最好了解向量内存分配的原理。然而,不要被其困扰。您编写的第一个游戏程序很可能不会受益于某种更加手动的向量内存分配方式。