环路内容器的性能
Performance of containers inside loops
我必须关心这样的代码吗:
for (int i=0; i < BIG; ++i) {
std::vector<int> v (10);
... do something with v ...
}
重构为:
std::vector<int> v;
for (int i=0; i < BIG; ++i) {
v.clear(); v.resize(10); // or fill with zeros
... do something with v ...
}
或者编译器足够聪明,可以优化内存分配?
我更喜欢第一个,因为当我不再需要std::vector<int> v
时,它就超出了范围。
在实践中,编译器很难为两者生成相同的代码,除非标准库的作者给它一些帮助。
特别是,vector
通常被模糊地实现为:
template <class T, class Allocator=std::allocator<T>>
class vector {
T *data;
size_t allocated_size, current_size;
public:
vector(size_t);
// ...
};
我简化了很多,但这足以证明我试图在这里提出的要点:向量对象本身不包含实际数据。矢量对象只包含一个指向数据的指针以及一些关于分配大小等的元数据。
这意味着,每次创建一个10 int的vector
时,vector
的构造函数都必须使用operator new
为(至少)10 int分配空间(从技术上讲,它使用传递给它的Allocator类型来实现这一点,但默认情况下,它将使用免费存储)。同样,当它超出范围时,它会使用分配器(同样,默认为空闲存储)来销毁10 int。
避免这种分配的一个明显方法是为向量对象本身内部的至少一小部分元素分配空间,并且只有当数据增长大于允许的空间时才在空闲存储上分配空间。这样,创建10 int的向量就相当于只创建一个10 int的数组(本地数组或std::array
)——在一台典型的机器上,当执行进入封闭函数时,它会在堆栈上分配,而进入块时发生的所有事情都是初始化内容(如果你试图在写入之前读取其中的一些)。
至少在一般情况下,我们不能这样做。例如,如果我移动赋值一个向量,则该移动赋值不能引发异常——即使单个元素的移动赋值会引发异常。因此,它不能对单个元素执行任何操作。有了上面这样的结构,这个要求就很容易满足了——我们基本上是从源到目的地进行一次浅层复制,并将源中的所有项清零。
然而,标准库中有一个容器确实允许进行优化:std::basic_string
特别允许。它最初看起来可能有点奇怪(老实说,有点奇怪),但如果用std::basic_string<int> v(10, 0);
替换std::vector
,并在包括短字符串优化(例如VC++)的实现中使用它,您可能会在速度上得到显著提高。std::string
允许这样做的方法之一是,您不能使用它来存储抛出异常的类型——如果int
只是一个例子,您可能真的需要存储其他可以抛出的类型,那么basic_string
可能不适合您。即使对于像int
这样的原生类型,char_traits<T>
也可能是一个不完整的类型,所以这可能无论如何都不起作用。如果你认为你非常需要,你可以把它作为你自己类型的容器,方法是1)确保它们不会抛出,2)专门为你的类型设置char_trait。一句话:尝试一下可能很有趣,但它很少(如果有的话)实用,而且几乎不可能推荐。
显而易见的替代方案是使用std::array<int, 10>
。如果数组的大小是固定的,那么这可能是首选。与在非字符类型上实例化basic_string
不同,您将按预期使用它,并获得其预期行为。缺点是大小是一个编译时常数,所以如果您可能需要在运行时更改大小,这根本不是一个选项。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 普通环路未使用gcc 4.8.5自动矢量化
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 哪种方法更好,性能明智
- C++ 特征库:引用的性能开销<>
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- 环路内开关的性能
- 环路内容器的性能