我正在创建一个大小为100的数组和向量,并生成一个随机值,并尝试将数组和向量维护为已排序。 这是我的代码
vector<int> myVector;
int arr[SIZE];
clock_t start, finish;
int random;
for(int i=0; i<SIZE;i++)
{
myVector.push_back(0);
arr[i] = 0;
}
//testing for Array
start = clock();
for(int i=0; i<MAX;++i)
{
random = getRandom(); //returns rand() % 100
for(int j=0; j<SIZE;++j){
if(random > arr[j])
{
for(int k = SIZE - 1; k > j ; --k)
{
arr[k] = arr[k-1];
}
arr[j] = random;
break;
}
}
}
finish = clock();
cout << "Array Time " << finish - start << endl;
//Vector Processing
start = clock();
for(int i=0; i<MAX;++i)
{
random = getRandom(); //returns rand() % 100
for(int j=0; j<SIZE;++j){
if(random > myVector[j])
{
for(int k = SIZE - 1; k > j ; --k)
{
myVector[k] = myVector[k-1];
}
myVector[j] = random;
break;
}
}
}
finish = clock();
cout << "Vector Time " << finish - start << endl;
输出如下:
数组时间:5
向量时间:83
在这种情况下,我无法理解为什么矢量与数组相比如此之慢? 这是否与优先使用Vector over Array的拇指规则相矛盾。
请帮助!
答案 0 :(得分:4)
首先:编程中的许多经验法则都不是关于性能的几毫秒,而是关于管理复杂性,因此避免了错误。在这种情况下,它是关于执行范围检查,大多数矢量实现在调试模式下执行,而数组不执行。它也是关于动态数组的内存管理 - 矢量确实管理它的内存本身,而你必须在数组中手动执行它而存在引入内存泄漏的风险(忘记delete[]
或使用delete
而不是?我是你的!)。这是关于易用性,例如调整矢量大小或在中间插入元素,这对于手动管理的数组来说是繁琐的工作
换句话说,性能测量永远不会违反经验法则,因为经验法则从不针对性能。性能测量只能是不遵守编码准则的几个可能原因之一。
乍一看,我猜你还没有启用优化。然后,向量性能损失的主要来源是索引检查,许多向量实现已启用调试版本。这些不会在优化的构建中发挥作用,因此这应该是您首先关注的问题。 经验法则:未启用优化的性能测量无意义
如果启用优化仍然可以为阵列显示更好的性能,那么还有另一个区别:
数组存储在堆栈中,因此编译器可以直接使用地址并在编译时计算地址偏移量,而向量元素存储在堆上,编译器必须取消引用存储在向量中的指针。我希望优化器一次取消引用指针并从该点计算地址偏移量。尽管如此,与编译时计算的地址偏移相比,可能会有一个小的性能损失,特别是如果优化器可以稍微展开循环。 这仍然与经验法则不矛盾,因为你在这里比较苹果和梨。经验法则说,
首选
std::vector
覆盖动态数组,而不是std::array
覆盖已修复的数组。
因此要么使用动态分配的数组(包括某种delete[]
),要么将固定大小的数组与std::array
进行比较。在C ++ 14中,您将不得不考虑游戏中的新候选者,即std::dynarray
和C ++ 14 VLA,不可调整大小的运行时长度数组,与C的VLA相当。
<强>更新强>
正如评论中指出的那样,优化器擅长识别没有副作用的代码,比如你从未读过的数组操作。 std::vector
实现非常复杂,优化器通常无法通过这几个间接层看到并优化掉所有插入,因此与向量的某个时间相比,您将获得零时间。在循环之后读取数组将禁用这种粗鲁的优化。
答案 1 :(得分:-1)
向量类必须动态增长内存,这可能涉及不时复制整个内容。 它还必须为许多操作调用内部函数 - 比如重新分配。 它也可能具有边界检查等安全功能。
与此同时,您的阵列已预先分配,并且您的所有操作都不会调用任何内部函数。
这是更多功能的间接费用。
谁说在所有情况下矢量应该比数组更快? 你的数组不需要增长,这就是数组确实更快的特殊情况!
答案 2 :(得分:-3)