假设我有一个我要排序的动态数组,我可以做
std::vector<int> v(100);
for (int i = 0; i < 100; i++) v[i] = rand();
std::sort(v.begin(), v.end());
但是对于性能关键代码,初始化开销是不可接受的,更多细节见https://stackoverflow.com/a/7269088/3667089
我也可以
int *v = new int[100];
for (int i = 0; i < 100; i++) v[i] = rand();
std::sort(v, v + 100);
但是我们自己管理内存必然会在大型代码库中发生内存泄漏。
所以似乎最可行的方法是
std::unique_ptr<int[]> v(new int[100]);
for (int i = 0; i < 100; i++) v[i] = rand();
std::sort(v, v + 100);
没有初始化开销也不需要担心内存管理,但这会返回一个很长的编译错误。有人能让我知道我做错了吗?
我在Ubuntu 14.04上,GCC是编译器。
编辑:更改代码,使数据尚未排序
答案 0 :(得分:11)
std::sort
仍然需要迭代器,unique_ptr
不是迭代器。但是,它确实保留了可以用作一个的东西:它的指针:
std::sort(v.get(), v.get() + 100);
或
std::sort(&*v, &*v + 100);
或
std::sort(&v[0], &v[0] + 100); // N.B. &v[100] invokes undefined behavior
但真正想要的是vector
分配器,默认初始化而不是value-initializes。这就是性能差异的来源 - 使用std::vector
和默认分配器将首先对所有int
进行零初始化,然后为它们分配一些值,而其他选项没有这个额外的零 - 初始化步骤。
查看Casey's执行此类操作,然后执行:
std::vector<int, default_init_allocator<int>> v(100); // not zero-initialized
for (int i = 0; i < 100; i++) v[i] = i;
std::sort(v.begin(), v.end());
一种不同的方法,在你不必处理分配器的意义上更简单(虽然在代码方面更烦人)是为int
引入一个包装器,其中值初始化不会做任何事情:
template <class T>
struct Wrapper {
Wrapper() { }
T value;
};
std::vector<Wrapper<int>> v(100); // not zero-initialized
for (int i = 0; i < 100; i++) v[i].value = i; // but have to do this...
请注意,仅使用reserve()
和push_back()
是不够的 - 除了在默认初始化之后通过索引分配,以及如果您对延迟敏感时,还需要做更多的工作足以问这个问题,这可能很重要。
答案 1 :(得分:4)
从问题中读取链接,如果它没有为每个元素调用不必要的构造函数,那么使用vector
似乎很高兴。有一些技术可以消除这种开销。
std::vector<int> v;
v.reserve(100);
for (int i = 0; i < 100; i++) v.emplace_back(rand());
std::sort(v.begin(), v.end());