C++标准库之std::begin、std::end、std::pre和std::next

 更新时间:2026年06月30日 09:21:17   作者:流星雨爱编程  
本文主要介绍了C++标准库之std::begin、std::end、std::pre和std::next,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.std::begin和std::end

std::begin()和std::end()是C++ STL中的函数模板,用于获取容器(数组、std::initializer_list、STL标准容器、std::string_view、std::array等)的起始和结束迭代器。它们提供了一种通用的方式来访问这些序列的边界,而不依赖于具体的容器类型。一般结合STL的算法一起使用,如:

int a[] = { 1, 3, 5, 2, 9, 6, 8 };
std::sort(std::begin(a), std::end(a));

它们的定义如下:

// FUNCTION TEMPLATES begin AND end
template <class _Container>
_NODISCARD _CONSTEXPR17 auto begin(_Container& _Cont) -> decltype(_Cont.begin()) {
    return _Cont.begin();
}

template <class _Container>
_NODISCARD _CONSTEXPR17 auto begin(const _Container& _Cont) -> decltype(_Cont.begin()) {
    return _Cont.begin();
}

template <class _Container>
_NODISCARD _CONSTEXPR17 auto end(_Container& _Cont) -> decltype(_Cont.end()) {
    return _Cont.end();
}

template <class _Container>
_NODISCARD _CONSTEXPR17 auto end(const _Container& _Cont) -> decltype(_Cont.end()) {
    return _Cont.end();
}

template <class _Ty, size_t _Size>
_NODISCARD constexpr _Ty* begin(_Ty (&_Array)[_Size]) noexcept {
    return _Array;
}

template <class _Ty, size_t _Size>
_NODISCARD constexpr _Ty* end(_Ty (&_Array)[_Size]) noexcept {
    return _Array + _Size;
}

从上面的定义来看:

1.1.begin()和end()参数为容器

当将某个具体容器(比如 cont)作为参数分别传给 begin() 和 end() 函数时,其中 begin() 底层会执行 cont.begin() 语句,而 end() 底层会执行 cont.end() 语句,它们最终会将得到的迭代器作为函数的返回值反馈回来。

当作用对象为容器时,end() 和 begin() 函数的语法格式是完全一样的,这里以 begin() 函数为例,有以下 2 种格式:

//① 非 const 修改的容器作为参数,begin() 函数返回的为非 const 类型的迭代器
template
auto begin (Container& cont)
//② 传入 const 修饰的容器,begin() 函数返回的为 const 类型的迭代器
template
auto begin (const Container& cont)

其中,cont 表示指定的容器;同时,函数会返回一个有特定指向的迭代器,且此迭代器的类型也取决于 cont 容器。
以上 2 种格式的区别仅在与传入的容器是否有 const 修饰,即如果有,则通过该函数获得的迭代器也有 const 修饰(不能用于修改容器中存储的数据);反之就没有。

#include <iostream>     // std::cout
#include <vector>       // std::vector, std::begin, std::end
using namespace std;
int main() {
    //创建并初始化 vector 容器
    std::vector<int> myvector{ 1,2,3,4,5 };
    //调用 begin() 和 end() 函数遍历 myvector 容器
    for (auto it = begin(myvector); it != end(myvector); ++it)
        cout << *it << ' ';
    return 0;
}

//程序执行结果为:
//1 2 3 4 5

//程序第 8 行中,begin(myvector) 等同于执行 myvector.begin(),
//而 end(myvector) 也等同于执行 myvector.end()。

1.2.begin()和end()参数为数组

除了可以将指定容器作为参数传给 begin() 和 end() 之外,还可以指定数组作为参数传给它们。

将指定数组传给 begin() 函数,其会返回一个指向该数组首个元素的指针;将指定数组传给 end() 函数,其会返回一个指向数组中最后一个元素之后位置的指针。

同样,数组作为参数时,end() 函数的语法格式和 begin() 函数也完全一样,这里仅给出了 begin() 函数的语法格式:

template <class T, size_t N>
T* begin (T(&arr)[N]);

其中 T 为数组中存储元素的类型,N 为数组的长度;(&arr)[N] 表示以引用的方式传递数组作为参数。

#include <iostream>     // std::cout
#include <vector>       // std::vector, std::begin, std::end
using namespace std;
int main() {
    //定义一个普通数组
    int arr[] = { 1,2,3,4,5 };
    //创建一个空 vector 容器
    vector<int> myvector;
    //将数组中的元素添加到 myvector 容器中存储
    for (int *it = begin(arr); it != end(arr); ++it)
        myvector.push_back(*it);
    //输出 myvector 容器中存储的元素
    for (auto it = myvector.begin(); it != myvector.end(); ++it)
        cout << *it << ' ';
    return 0;
}
//程序执行结果为:
//1 2 3 4 5

举个例子:
注意程序中第 10 行,这里用整数指针 it 接收 begin(arr) 的返回值,同时该循环会一直循环到 it 指向 arr 数组中最后一个元素之后的位置。

1.3.用户自定义重载

可以为不暴露适合的 begin()和end()成员函数的类提供 begin 和end的自定义重载,从而能迭代它。标准库已提供下列重载:

std::begin(std::initializer_list)

(C++11)

std::end(std::initializer_list)

(C++11)

特化 std::begin和std::end
(函数模板)

std::begin(std::valarray)

(C++11)

std::end(std::valarray)

(C++11)

特化的 std::begin和std::end
(函数模板)

begin(std::filesystem::directory_iterator)end(std::filesystem::directory_iterator)

基于范围的 for 循环支持
(函数)

begin(std::filesystem::recursive_directory_iterator)end(std::filesystem::recursive_directory_iterator)

基于范围的 for 循环支持
(函数)

同 swap 的使用(描述于可交换 (Swappable) ), begin 函数在泛型语境中的使用等价于 using std::begin; begin(arg);,end 函数在泛型语境中的典型使用等价于 using std::end; end(arg); 这允许 ADL 为用户定义类型所选的重载和出现于同一重载集的标准库函数模板。

template<typename Container, typename Function>
void for_each(Container&& cont, Function f) {
    using std::begin;
    auto it = begin(cont);
    using std::end;
    auto end_it = end(cont);
    while (it != end_it) {
        f(*it);
        ++it;
    }
}

2.std::pre和std::next

在C++标准库中,std::prev 和 std::next 是两个常用的函数模板,用于在迭代器上进行向前或向后的操作。它们分别用于获取给定迭代器的前一个或后一个迭代器。这些函数模板定义在头文件 <iterator> 中。

它们的定义如下:

// FUNCTION TEMPLATE _Next_iter
template <class _InIt>
constexpr _InIt _Next_iter(_InIt _First) { // increment iterator
    return ++_First;
}

// FUNCTION TEMPLATE next
template <class _InIt>
_NODISCARD _CONSTEXPR17 _InIt next(_InIt _First, _Iter_diff_t<_InIt> _Off = 1) { // increment iterator
    static_assert(_Is_input_iter_v<_InIt>, "next requires input iterator");

    _STD advance(_First, _Off);
    return _First;
}

// FUNCTION TEMPLATE _Prev_iter
template <class _BidIt>
constexpr _BidIt _Prev_iter(_BidIt _First) { // decrement iterator
    return --_First;
}

// FUNCTION TEMPLATE prev
template <class _BidIt>
_NODISCARD _CONSTEXPR17 _BidIt prev(_BidIt _First, _Iter_diff_t<_BidIt> _Off = 1) { // decrement iterator
    static_assert(_Is_bidi_iter_v<_BidIt>, "prev requires bidirectional iterator");

    _STD advance(_First, -_Off);
    return _First;
}

注意:std::prev 和 std::next 要求迭代器至少是双向迭代器(BidirectionalIterator),这意味着它必须支持向前和向后移动。

以下是一个简单的示例,演示如何使用 std::prev 和 std::next:

#include <iostream>  
#include <vector>  
#include <iterator>  
  
int main() {  
    std::vector<int> vec = {1, 2, 3, 4, 5};  
  
    auto it = vec.begin();  
  
    // 使用 std::next  
    auto next_it = std::next(it, 2); // 指向 vec[2] 即 3  
    std::cout << "Element pointed by next_it: " << *next_it << std::endl;  
  
    // 使用 std::prev  
    auto prev_it = std::prev(next_it, 1); // 指向 vec[1] 即 2  
    std::cout << "Element pointed by prev_it: " << *prev_it << std::endl;  
  
    return 0;  
}

3.总结

  • std::begin 用于获取给定容器的起始迭代器。
  • std::end 用于获取给定容器的结束迭代器。
  • std::prev 用于获取给定迭代器的前一个迭代器。
  • std::next 用于获取给定迭代器的后一个迭代器。
  • 它们分别要求迭代器至少是双向迭代器(对于 std::prev)和前向迭代器(对于 std::next)。

这四个函数模板在遍历容器或处理迭代器时非常有用,可以简化代码并增加可读性。

到此这篇关于C++标准库之std::begin、std::end、std::pre和std::next的文章就介绍到这了,更多相关C++ std::begin、std::end、std::pre和std::next内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现进制转换函数的实例详解

    C语言实现进制转换函数的实例详解

    这篇文章主要介绍了C语言实现进制转换函数的实例详解的相关资料,这里提供实现实例帮助大家实现改功能,需要的朋友可以参考下
    2017-08-08
  • C++小知识:用合适的工具来分析你的代码

    C++小知识:用合适的工具来分析你的代码

    今天小编就为大家分享一篇关于C++小知识:用合适的工具来分析你的代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • C语言哈希表概念超详细讲解

    C语言哈希表概念超详细讲解

    哈希是一种很高效的存储数据的结构,它是利用的一种映射关系,它也是STL中unordered_map和unordered_set 的底层结构。本文,主要讲解哈希的原理,哈希的实现,里面关键点在于如何解决哈希冲突
    2023-02-02
  • C++文件输入输出fstream使用方法

    C++文件输入输出fstream使用方法

    C++标准库提供了<fstream>头文件,其中包含了用于文件输入输出的相关类和函数,本文将详细介绍<fstream>头文件的使用方法,包括函数原型、打开文件、读取和写入文件、以及错误处理等注意事项,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • C++日历拼图的解法你了解吗

    C++日历拼图的解法你了解吗

    这篇文章主要为大家详细介绍了日历拼图C++的解法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • C++指针运算符(&和*)的实现

    C++指针运算符(&和*)的实现

    C++ 提供了两种指针运算符,一种是取地址运算符 &,一种是间接寻址运算符 *,本文就详细的介绍一下这两种运算符的使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • C++ pair方法与vector方法案例详解

    C++ pair方法与vector方法案例详解

    这篇文章主要介绍了C++ pair方法与vector方法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • C++实现五子棋游戏(注释版)

    C++实现五子棋游戏(注释版)

    这篇文章主要为大家详细介绍了C++实现五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言强制类型转换规则实例详解

    C语言强制类型转换规则实例详解

    强制类型转换是把变量从一种类型转换为另一种数据类型,下面这篇文章主要给大家介绍了关于C语言强制类型转换的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C语言数组栈实现模板

    C语言数组栈实现模板

    这篇文章主要为大家详细介绍了C语言数组栈实现模板,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12

最新评论