GVKun编程网logo

std::vector 比普通数组慢很多吗?(std::vector data)

1

此处将为大家介绍关于std::vector比普通数组慢很多吗?的详细内容,并且为您解答有关std::vectordata的相关问题,此外,我们还将为您介绍关于cstd::vectorstd::sort

此处将为大家介绍关于std::vector 比普通数组慢很多吗?的详细内容,并且为您解答有关std::vector data的相关问题,此外,我们还将为您介绍关于c std :: vector std :: sort无限循环、c – std :: list,std :: vector方法和malloc()、c – std :: vector :: insert保留定义吗?、c – std :: vector :: iterator可以只是T *吗?的有用信息。

本文目录一览:

std::vector 比普通数组慢很多吗?(std::vector data)

std::vector 比普通数组慢很多吗?(std::vector data)

我一直认为这std::vector是“作为数组实现”的普遍智慧,等等等等。今天下楼测试了一下,好像不是这样:

以下是一些测试结果:

UseArray completed in 2.619 secondsUseVector completed in 9.284 secondsUseVectorPushBack completed in 14.669 secondsThe whole thing completed in 26.591 seconds

这大约慢了 3 - 4 倍!并不能真正证明“vector可能会慢几纳秒”的评论。

我使用的代码:

#include <cstdlib>#include <vector>#include <iostream>#include <string>#include <boost/date_time/posix_time/ptime.hpp>#include <boost/date_time/microsec_time_clock.hpp>class TestTimer{    public:        TestTimer(const std::string & name) : name(name),            start(boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time())        {        }        ~TestTimer()        {            using namespace std;            using namespace boost;            posix_time::ptime now(date_time::microsec_clock<posix_time::ptime>::local_time());            posix_time::time_duration d = now - start;            cout << name << " completed in " << d.total_milliseconds() / 1000.0 <<                " seconds" << endl;        }    private:        std::string name;        boost::posix_time::ptime start;};struct Pixel{    Pixel()    {    }    Pixel(unsigned char r, unsigned char g, unsigned char b) : r(r), g(g), b(b)    {    }    unsigned char r, g, b;};void UseVector(){    TestTimer t("UseVector");    for(int i = 0; i < 1000; ++i)    {        int dimension = 999;        std::vector<Pixel> pixels;        pixels.resize(dimension * dimension);        for(int i = 0; i < dimension * dimension; ++i)        {            pixels[i].r = 255;            pixels[i].g = 0;            pixels[i].b = 0;        }    }}void UseVectorPushBack(){    TestTimer t("UseVectorPushBack");    for(int i = 0; i < 1000; ++i)    {        int dimension = 999;        std::vector<Pixel> pixels;            pixels.reserve(dimension * dimension);        for(int i = 0; i < dimension * dimension; ++i)            pixels.push_back(Pixel(255, 0, 0));    }}void UseArray(){    TestTimer t("UseArray");    for(int i = 0; i < 1000; ++i)    {        int dimension = 999;        Pixel * pixels = (Pixel *)malloc(sizeof(Pixel) * dimension * dimension);        for(int i = 0 ; i < dimension * dimension; ++i)        {            pixels[i].r = 255;            pixels[i].g = 0;            pixels[i].b = 0;        }        free(pixels);    }}int main(){    TestTimer t1("The whole thing");    UseArray();    UseVector();    UseVectorPushBack();    return 0;}

我做错了什么吗?还是我刚刚打破了这个性能神话?

我在Visual Studio
2005中使用发布模式。


在Visual
C++中,#define_SECURE_SCL 0减少UseVector一半(减少到 4 秒)。这真的很大,IMO。

答案1

小编典典

使用以下内容:

g++ -O3 Time.cpp -I
./a.out
UseArray
在 2.196 秒内完成 UseVector 在 4.412 秒内
完成 UseVectorPushBack在 8.017 秒内完成
整个事情在 14.626 秒内完成

所以数组的速度是向量的两倍。

但是
在更详细地查看代码之后,这是可以预期的;当您两次运行向量并且仅运行一次数组时。注意:当你resize()使用向量时,你不仅要分配内存,还要运行向量并调用每个成员的构造函数。

稍微重新排列代码,使向量只初始化每个对象一次:

 std::vector<Pixel>  pixels(dimensions * dimensions, Pixel(255,0,0));

现在再次做同样的时间:

g++ -O3 Time.cpp -I
./a.out
UseVector 在 2.216 秒内完成

向量现在的性能只比数组差一点。IMO 这种差异是微不足道的,可能是由一大堆与测试无关的事情引起的。

我还要考虑到您没有正确初始化/销毁UseArrray()方法中的 Pixel
对象,因为没有调用构造函数/析构函数(这对于这个简单的类可能不是问题,但稍微复杂一点(即使用指针或成员)带指针)会导致问题。

c std :: vector std :: sort无限循环

c std :: vector std :: sort无限循环

每当我试图对导致无限循环的对象矢量进行排序时,我就遇到了一个问题.我正在使用我传递给sort函数的自定义比较函数.

我能够通过在两个对象相等而不是true时返回false来解决问题但我并不完全理解解决方案.我认为这是因为我的比较功能违反了cplusplus.com上列出的规则:

Comparison function object that,
taking two values of the same type
than those contained in the range,
returns true if the first argument
goes before the second argument in the
specific strict weak ordering it
defines,and false otherwise.

任何人都可以提供更详细的解释吗?

解决方法

正如其他人所指出的那样,正确的答案是要了解“严格的弱排序”是什么.特别是,如果comp(x,y)为真,则comp(y,x)必须为假. (注意,这意味着comp(x,x)为false.)

这就是解决问题所需要知道的全部内容.如果您的比较函数违反规则,则排序算法根本不做任何承诺.

如果你好奇实际上出了什么问题,那么你的库的排序例程可能会在内部使用quicksort. Quicksort通过在序列中反复找到一对“乱序”元素并交换它们来工作.如果您的比较告诉算法a,b是“乱序”,并且它还告诉算法b,a是“乱序”,那么算法可以最终来回交换它们.

c – std :: list,std :: vector方法和malloc()

c – std :: list,std :: vector方法和malloc()

在中断处理程序下使用stl:list和stl :: vector类型我想避免malloc()调用.

问题:在STL列表和向量中阻止malloc()调用的最佳方法是什么?是否足以创建具有预定义大小的结构,然后避免推/弹/擦除调用?

先感谢您

解决方法

作为推荐:我们在我的工作场所使用其他答案中提到的两种方法:

>自定义分配器:对于我们的内存泄漏跟踪系统,我们的仪器分析器和一些其他系统,我们使用提供的分配器预分配和/或“池”(参见例如boost :: pool)分配 – 通常用于std :: set或std :: map,但std :: list的原理相同.
> reserve / resize:对于std :: vectors,我们提前保留或调整大小(差异很重要,但两者都可以帮助避免将来的分配)是非常常见的做法.

大多数情况下,我们会做这两件事以避免碎片,减少分配器开销,消除复制增加的惩罚等.但有时(特别是对于仪表分析器)我们希望绝对避免在中断处理程序中进行分配.

但是,通常我们会以其他方式避免中断和分配问题:

>进入/退出:尽量避免在中断期间执行除标志或普通副本之外的任何操作;有时静态(或预分配)缓冲区是比STL容器好得多的解决方案.持续中断时间过长通常会导致灾难.
>在alloc / free期间禁用中断:在我们分配/释放时,中断排队,而不是立即调度 – 这是我们正在使用的cpu的一个功能.结合有选择地增加禁用/排队范围的策略(例如std :: list操作),我们有时可以使用中断处理程序作为生产者,一切 – 其他作为消费者模型,而不是覆盖分配器.如果我们正在从std :: list中消费某些东西(例如从网络硬件接收到的消息),那么中断会在尽可能短的时间内排队,同时弹出我们即将处理的内容的副本.

请注意,无锁数据结构可以替代此处的第二个项目符号,我们还没有设置和完成分析以查看它是否有用.无论如何,设计自己的业务是棘手的事情.

对于中断处理程序来说,偏执狂是更好的部分:如果你不确定你所做的事情会起作用,那么以一种完全不同的方式解决问题有时会好得多.

c – std :: vector :: insert保留定义吗?

c – std :: vector :: insert保留定义吗?

在std :: vector上调用insert成员函数时,它会在“推回”新项目之前保留吗?我的意思是标准保证与否?

换句话说,我应该这样做:

std::vector<int> a{1,2,3,4,5};
std::vector<int> b{6,7,8,9,10};
a.insert(a.end(),b.begin(),b.end());

或者像这样:

std::vector<int> a{1,10};
a.reserve(a.size()+b.size());
a.insert(a.end(),b.end());

还是其他更好的方法?

解决方法

关于函数 [link]的复杂性:

Linear on the number of elements inserted (copy/move construction)
plus the number of elements after position (moving).

Additionally,if InputIterator in the range insert (3) is not at least
of a forward iterator category (i.e.,just an input iterator) the new
capacity cannot be determined beforehand and the insertion incurs in
additional logarithmic complexity in size (reallocations).

因此,有两种情况:

>可以确定新容量,因此您无需拨打预留>新的容量无法确定,因此保留呼叫应该是有用的.

c – std :: vector :: iterator可以只是T *吗?

c – std :: vector :: iterator可以只是T *吗?

简单的理论问题:一个简单的指针是std :: vector的有效迭代器类型吗?

对于其他容器(例如list,map),这是不可能的,但对于std :: vector,保证数据是连续的,所以我认为没有理由不这样做.

据我所知,一些实现(例如Visual Studio)对调试版本进行了一些安全检查.但这是在UB领域,所以对于定义明确的行为,我认为没有区别.

除了一些检查(“修改”未定义的行为),使用类而不是简单的指针用于向量迭代器有什么好处吗?

解决方法

would a simple pointer be a valid iterator type for std::vector?

是.还有std :: basic_string和std :: array.

are there any advantages of using a class instead of a simple pointer for vector iterators?

它提供了一些额外的类型安全性,因此如下所示的逻辑错误无法编译:

std::vector<int> v;
int i=0;
int* p = &i;
v.insert(p,1); // oops,not an iterator!
delete v.begin();  // oops!

std::string s;
std::vector<char> v;
// compiles if string and vector both use pointers for iterators:
v.insert(s.begin(),'?');
std::array<char,2> a;
// compiles if array and vector both use pointers for iterators:
v.erase(a.begin());

今天关于std::vector 比普通数组慢很多吗?std::vector data的介绍到此结束,谢谢您的阅读,有关c std :: vector std :: sort无限循环、c – std :: list,std :: vector方法和malloc()、c – std :: vector :: insert保留定义吗?、c – std :: vector :: iterator可以只是T *吗?等更多相关知识的信息可以在本站进行查询。

本文标签: