C++的string就是一个看起来不错的例子,但是在效率极其重要的场合应该避免使用,考虑下面的代码。
Void Function(const std::string &str)
{
}
Function("hello");
对Function()的调用包括了对给定const char*参数的构造函数的调用。在普遍的实现中,这个构造函数执行了一个malloc(),一个strlen(),以及一个memcpy(),而析构函数立刻上来做了一些无意义的事情。(由于该例子中的string没有被更多的应用)然后又跟了一个free()。这里的内存分配完全是浪费,因为字符串“hello”早就在程序的数据段中了。我们早就有它在内存中的副本了。如果Function定义了一个const char*的参数,那么完全没有了上面所说的那些额外的调用。这就是为了使用方便的string而付出的高昂代价。
模板是效率的对立面的一个例子,根据语言标准,编译器在模板实例化为一个具体的类型时产生代码。理论上,看上去是声明了一个模板,但却实际产生了大量的相似的代码。如果你有了class1的指针的vector,也有class2的指针的vector,你就在你的可执行文件中做了两份的vector的拷贝。
事实上,大多数的编译器做得更好,首先,只有实际被使用到的模板成员函数被产生代码。其次,如果事先了解了正确的行为,编译器可以只产生一份代码的拷贝。你可以从vector的例子发现这一点,确实只产生了一份代码(一般是vector )。有了好的编译器,模板还是可以在保持高效的同时提供你一般编程的好处。
C++的一些特性,比如初始化列表以及前自增,一般来说可以提高效率。而象其它的一些特性比如运算符重载以及RTTI则看起来似乎是清白的,但却有时带来严重的效率问题。STL的容器则描述了盲目相信函数的算法运行时间可以如何让你误入歧途。避免使用潜在的低效率的语言或类库特性,同时花些时间来了解你的编译器的各种选项。你会很快的学会设计高效的代码,并且解决掉你的游戏中的效率问题。
7、其他参考
Thanks to Pete Isensee and Christopher Kirmse reviewing this gem.
Cormen, Thomas, Charles Leiserson, and Ronald Rivest, Introduction to Algorithms, Cambridge, Massachusetts, MIT Press, 1990
Isensee, Peter, C++ Optimization Strategies and Techniques, www.tantalon.com/pete/cppopt/main.htm Koenig, Andrew "Pre-or Postfix Increment"
The C++ Report, June,1999 Meyers, Scott, Effective C++, Second Edition, Reading, Massachusetts: Addison-Wesley Publishing Co., 1998.
Sutter, Herb, Guru of the Week #54: Using Vector and Deque, www.gotw.ca/gotw/054.htm