c++ vector::开始()和std::begin()的区别

o4hqfura  于 2023-04-01  发布在  其他
关注(0)|答案(3)|浏览(350)

在c++中迭代向量时,我注意到标准库中有一个begin()函数,vector类的成员函数也有一个begin()函数。如果有的话,两者之间有什么区别,应该使用哪个?
示例:

vector<int> numbers;
//Code to put values in my vector
for (vector<int>::iterator i = numbers.begin(); i < numbers.end(); i++)
    cout << *i << '\n';

对比:

vector<int> numbers;
//Code to put values in my vector
for (vector<int>::iterator i = std::begin(numbers); i < std::end(numbers); i++)
    cout << *i << '\n';
wd2eg0qa

wd2eg0qa1#

std::begin()是在C++11中添加的,以便更容易编写泛型代码(例如在模板中)。最明显的原因是普通C风格的数组没有方法,因此没有.begin()。因此您可以将std::begin()用于C风格的数组,以及具有自己的begin()end()的STL风格容器。
如果你写的代码不是模板,你可以忽略std::begin();如果你突然开始到处使用它,仅仅因为它是新的,你的程序员同事可能会觉得奇怪。

osh3o9ms

osh3o9ms2#

向量的std::begin()的实现简单地调用std::vector<T>::begin(),因此在这种情况下两者之间没有区别。
std::begin()在泛型算法中发挥了作用:

template<typename Container>
void my_algorithm(Container c) {
    using std::begin;
    using std::end;
    auto const start = begin(c);  // ADL will find the appropriate overload
    auto const finish = end(c);
    // ... rest of code ...
}
f3temu5u

f3temu5u3#

如果你的编译器优化了你的代码,那么你使用哪一种格式并不重要。否则,你可能想使用更面向对象的格式:numbers.开始()
此代码已插入Quick Bench进行速度测量:

std::vector<int> arr = {0,1,2};

static void formatA(benchmark::State& state) {
  for (auto _ : state) { // Code inside this loop is measured repeatedly
    std::vector<int>::iterator itrA = arr.begin(); // arr.end();
    benchmark::DoNotOptimize(itrA);
  }
}
// Register the function as a benchmark
BENCHMARK(formatA);

static void formatB(benchmark::State& state) {
  for (auto _ : state) { // Code before the loop is not measured
    std::vector<int>::iterator itrB = begin(arr); // end(arr);
    benchmark::DoNotOptimize(itrB);
  }
}
BENCHMARK(formatB);

全部使用STL=libstdc++(GNU)编译,begin()的结果如下:
| params \ cpu_time(4dp)|格式A|格式B|结论|
| --------------|--------------|--------------|--------------|
| optim = none
compiler = Clang 11.0
std = c++11
|一九一四年二月|5.1870|A比B快2.4倍|
| optim = none
compiler = Clang 15.0
std = c++20
|2.0666|2.8974|A比B快1.4倍|
| optim = O3
compiler = Clang 11.0
std = c++11
|1.1094|1.0130|大致等效运行时间(等效组件)|
| optim = O3
compiler = Clang 15.0
std = c++20
|一○ ○九三|一点零零零七|大致等效运行时间(等效组件)|
而对于end()
| params \ cpu_time(4dp)|格式A|格式B|结论|
| --------------|--------------|--------------|--------------|
| optim = none
compiler = Clang 11.0
std = c++11
|2.5166|2.6341|大致等效运行时间|
| optim = none
compiler = Clang 15.0
std = c++20
|二点三六五七|3.8461|A比B快1.6倍|
| optim = O3
compiler = Clang 11.0
std = c++11
|1.0045|1.0126|大致等效运行时间(等效组件)|
| optim = O3
compiler = Clang 15.0
std = c++20
|1.0047|1.0012|大致等效运行时间(等效组件)|
如果没有优化,
formatA callq s <std::vector<int, std::allocator<int> >::begin()>end(),而
formatB callq s <decltype (({parm#1}.begin)()) std::begin<std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >&)>end()也分别是。推导formatB的数据类型会浪费时间。
通过优化,编译器已经完成了推导,两者都将使用以下程序集,并且除了地址之外没有其他变化:

mov    0x3c5b1(%rip),%rax        # 24f188 <arr>
mov    %rax,0x8(%rsp)
add    $0xffffffffffffffff,%rbx

相关问题