C++ 是否可以对std::unique应用std::sort<;T[]>;?

C++ 是否可以对std::unique应用std::sort<;T[]>;?,c++,c++11,heap-memory,unique-ptr,C++,C++11,Heap Memory,Unique Ptr,假设我有一个要排序的动态数组,我可以 std::vector<int> v(100); for (int i = 0; i < 100; i++) v[i] = rand(); std::sort(v.begin(), v.end()); 标准:向量v(100); 对于(inti=0;i标准向量…选项3是UB;它打破了操作符[]上的一个要求。有一些检查会减慢向下推_的速度,请参阅@user3667089,当您能够测量一个分支(这将通过第四次迭代的分支预测消除)和非原子增量的性

假设我有一个要排序的动态数组,我可以

std::vector<int> v(100);
for (int i = 0; i < 100; i++) v[i] = rand();
std::sort(v.begin(), v.end());
标准:向量v(100); 对于(inti=0;i<100;i++)v[i]=rand(); 排序(v.begin(),v.end()); 但是对于性能关键的代码,初始化开销是不可接受的,更多详细信息请参见

我也可以

int *v = new int[100];
for (int i = 0; i < 100; i++) v[i] = rand();
std::sort(v, v + 100);
int*v=newint[100];
对于(inti=0;i<100;i++)v[i]=rand();
标准::排序(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);
std::unique_ptr v(新整数[100]);
对于(inti=0;i<100;i++)v[i]=rand();
标准::排序(v,v+100);
没有初始化开销,也不需要担心内存管理,但这会返回一个较长的编译错误。有人能告诉我我做错了什么吗

我使用Ubuntu 14.04,GCC作为编译器


编辑:更改代码,使数据未排序

std::sort
仍然需要迭代器,并且
unique\u ptr
不是迭代器。但是,它确实保留了一些可以用作一个的东西:它的指针:

std::sort(v.get(), v.get() + 100);


但是您真正想要的是一个
向量
分配器,它默认初始化,而不是值初始化。这就是性能差异的来源-使用默认分配器的
std::vector
将首先对所有
int
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());

请注意,简单地使用
reserve()
push_back()
是不够的-这仍然需要做的工作比默认初始化后简单地按索引分配要多,如果您对延迟足够敏感,可以问这个问题,这可能很重要。

阅读问题中的链接,如果不为每个元素调用不必要的构造函数,那么使用
向量
似乎会很高兴。有一些技术可以消除这种开销

std::vector<int> v;
v.reserve(100);
for (int i = 0; i < 100; i++) v.emplace_back(rand());
std::sort(v.begin(), v.end());
std::vector v;
v、 储备(100);
对于(int i=0;i<100;i++)v.emplace_back(rand());
排序(v.begin(),v.end());

std::sort(v.get(),v.get()+100)
?@KerrekSB哇,这太快了,太正确了。如果你写一个答案,我会接受。(顺便问一下,你的数据已经排序了…)你分配了多少这些项目?有一个自定义分配器,从一个大的、预先分配的内存板中提取,可以解决您的问题。请注意,您使用的GCC版本通常比涉及的任何操作系统都更相关。因此,您试图解决的真正问题是向量的快速初始化?选项2很有趣。:)以下是非初始化分配器如何影响codegen的一小部分。注意:如果
*v
有一个重载的
运算符&
,则2和3都会失败,因此不应在泛型代码中使用。寓意:通用代码是不可能编写的。我只是测量了时间,速度方面的原始指针>casey的默认向量>唯一的ptr>标准向量,我不太明白为什么,因为我希望原始指针=casey的默认向量=唯一的ptr>标准向量…选项3是UB;它打破了
操作符[]
上的一个要求。有一些检查会减慢向下推_的速度,请参阅@user3667089,当您能够测量一个分支(这将通过第四次迭代的分支预测消除)和非原子增量的性能影响时,请给我打电话。@mark悲哀地说,在
std::vector
中没有
emplace\u back\u我知道\u capacity
方法,我还没有在任何评测测试(或任何ASM输出)中看到编译器的结果。也许你可以证明我错了,我至少有一年没有找过了。@SergeyA你可以很容易地衡量绩效影响。如果你写了一个基准测试,你会发现有很大的不同。@Barry如果初始化很简单,比如常量或递增值,这可能是真的。如果正在进行任何生成值的工作,例如问题中的
rand
,那么差异很快就会变得无关紧要。是的,它仍然是可以测量的,并且C++仍然允许你在需要时写入裸露的金属。这个答案只是试图突破你不需要英勇努力就能达到的极限。
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());
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... 
std::vector<int> v;
v.reserve(100);
for (int i = 0; i < 100; i++) v.emplace_back(rand());
std::sort(v.begin(), v.end());