template <typename T>
std::vector<T> drop(int size, const std::vector<T>& coll){
if (size<0) return std::vector<T>();
auto sized = size > coll.size() ? coll.size() : size;
typename std::vector<T>::const_iterator first = coll.begin()+sized;
typename std::vector<T>::const_iterator last = coll.end();
return std::vector<T>(first,last);
}
template <typename T>
std::vector<T> drop2(int size, std::vector<T> coll){
if (size<0) return std::vector<T>();
auto sized = size > coll.size() ? coll.size() : size;
coll.erase(coll.begin(),coll.begin()+sized);
return coll;
}
在这两个版本中,都会分配一个新的
std::vector
(在第二个版本中,它被作为参数复制,而不是引用)。其中一个通过erase()
创建结果,而另一个则使用原始向量的迭代器创建结果。有没有理由认为这两者在性能上有实质性的区别?
此外,在这两个版本中,RVO是否有保障?
编辑:
我做了一个测试,结果表明第一个版本比第二个版本慢很多。
template<typename F>
void dropExample(F f){
std::cout<<"drop example"<<std::endl;
auto t1 = Clock::now();
for (auto x: range(100000)){
f(2, range(100));
}
auto t2 = Clock::now();
std::cout << "Delta t2-t1: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
<< " ms" << std::endl;
}
输出:
dropExample(drop<int>);
dropExample(drop2<int>);
drop example
Delta t2-t1: 625 ms
drop example
Delta t2-t1: 346 ms
无论我在for循环中添加多少次迭代,即使是进行十秒钟的操作,数字也大致如此。
编辑2:
我已经按照评论建议增加了lvalue测试:
template<typename F, typename T>
void dropExample2(F f, T vec){
std::cout<<"drop example 2"<<std::endl;
auto t1 = Clock::now();
for (auto x: range(1000)){
f(2, vec);
}
auto t2 = Clock::now();
std::cout << "Delta t2-t1: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
<< " ms" << std::endl;
}
然后在主函数中:
int main(int argc, const char * argv[]) {
auto testrange=range(100000);
dropExample(drop<int>);
dropExample(drop2<int>);
dropExample2(drop<int>,testrange);
dropExample2(drop2<int>,testrange);
return 0;
}
输出结果仍然表明第二个更快:
drop example
Delta t2-t1: 564 ms
drop example
Delta t2-t1: 375 ms
drop example 2
Delta t2-t1: 2318 ms
drop example 2
Delta t2-t1: 698 ms
以下是示例中使用的辅助函数:
```
std::vector<int> range(int start, int end, int step);
std::vector<int> range(int start, int end){
if (end<start){
return range(start,end,-1);
}else if (start == end){
return std::vector<int> {start};
}else{
std::vector<int> nums(end-start);
std::iota(nums.begin(),nums.end(),start);
return nums;}
}
std::vector<int> range(int end){
return range(0,end);
}
std::vector<int> range(int start, int end, int step){
std::vector<int> nums{start};
auto next=start+step;
while ((next<end&&start<=end&&step>0)||
(next>end&&start>end&&step<0))
{
nums.push_back(next);
next+=step;
}
return nums;
}
erase
。由于erase
可能是一堆移动操作和可能是复制操作,所以它会更快。尝试提供一个左值。由于你正在处理int
,所以只需要进行复制操作。但是第二个测试不需要分配内存。 - jaggedSpirerange
和logit
?我们需要一个可编译的示例。 - NathanOliver