一、预分配动态变量以防止重新分配
动态变量带来的便利实在太多了,我首先想到的是std::string,但这并不意味着开发人员可以大意,当使用标准库容器时,总是有技术可以帮助我们减少内存分配的次数。
随着std::string,std::vector上数据的增加,它内部的动态分配的存储空间终究会枯竭,下一个添加的操作会导致需要分配更大的存储空间,以及将旧的数据赋值到新存储空间中,对内存管理器的调用以及复制操作将会多次访问内存并消耗指令,对于这个问题其实是由解决方法的。
string和vector都有成员函数reserve(size_t n),调用该函数会告诉string或是vector请确保至少由n个元素的空间。如果可以事先计算或预估出这个大小,那么调用reserve()为string或是vector予留足够的内部存储空间,可以避免出现他们到达增长极限后需要重新分配存储空间的情况。
int main()
{
string str;
cout << sizeof(str) << endl;
str.reserve(100);
str = "hello world,";
str += "I am a programmer!";
cout << str.c_str() << endl;
system("pause");
return 0;
}
大家不用太过担心reserve(),这仅仅是对string和vector的一种提示,即使过小地估计了予留的容量,惩罚就是,大不了额外的重新分配。而即使过大的估计,只要string,vector会在短暂地使用后销毁,就都没有问题。其实在使用了reserve()后,也可以使用shrink_to_fit()成员函数将未使用的空间返回给内存管理器。
二、在循环外创建动态变量
由如下的代码
for (auto &filename:namelist)
{
std::string config;
ReadFileXML(filename,config);
ProcessXML(config);
}
上述代码每次循环都会创建config,并且每次循环内部,都会重新分配内存,接着在循环末尾离开了作用域后,config将会被销毁。提高这段代码的性能就是将config移动到循环外,如下:
std::string config;
for (auto &filename:namelist)
{
confg.clear();
ReadFileXML(filename,config);
ProcessXML(config);
}
注意,clear()函数并不会释放config内部的动态缓冲区,它只是将config的内容长度设置为0,从第二次循环开始,只要接下来的文件没有比第一循环使用的空间大,就不会重新分配内存。
这种方式,不仅适用于std::string,也适用于std::vector和其它任何拥有动态大小骨架的数据结构。
之外:在Effective C++中有一节尽可能延后变量定义的出现时间的知识点,其实和这节并不冲突,因为它分为非循环和循环两部分,对于非循环语句中毋庸置疑,而在循环中还是要以构造函数代价于析构函数代价综合考虑。如果构造函数和析构函数的代价大于赋值代价则放到循环外,否则放到循环内。