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

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

C++ primer (中文版第四版)第273页 9.3.2 beginend成员         beginend操作产生指向容器内第一个元素和最后一个元素的下一个位置的迭代器,如下所示。这两个迭代器通常用于标记包含容器中所有元素的迭代范围。 c.begin() 返回一个迭代器,它指向容器c的第一个元素 c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置 std::vector<int> v1{ 1,1,1, 2, 5, 5, 5, 9 }; for (auto iter = std::begin(v1); iter != std::end(v1); iter = st 特性解决的问题核心优势std::begin容器与数组迭代器获取方式不统一泛型代码可同时支持容器、数组、自定义类型std::end原生数组尾后迭代器需手动计算长度避免硬编码长度,降低数组越界风险std::next迭代器移动需手动循环或区分迭代器类型统一接口,自动适配迭代器类别,兼顾效率与通用性std::prev反向移动迭代器操作繁琐简化"前n个位置"访问,仅需关注逻辑而非实现细节C++11的std::beginstd::endstd::nextstd::prev看似简单,实则是。 for遍历元素 C++11增加了一个行特性foreach(Range-based for loops ,基于范围的for循环)。可以对集合、数组、初始化列逐个访问。 for ( range_declaration : range_expression) loop_statement // 第一种 template < class ForwardIt> ForwardIt next(ForwardIt it, typename std::iterator_traits<ForwardIt>::difference_type = 1); // 第二种 template<class InputId> const... 函数功能修改原始迭代器返回新迭代器std::next将迭代器向前移动n步否是std::prev将迭代器向后移动n步否是将迭代器向前或向后移动n步是否便捷获取目标位置的迭代器:无需手动调用迭代器的递增操作。与算法配合使用:例如在std::find或等算法中定位迭代器。安全性:不直接修改原始迭代器,提高代码的清晰度和可读性。 C++ STL标准库提供的所有容器做了系统的讲解。无论是序列式容器还是关联式容器(包括哈希容器),不仅模板类内部提供有 begin() 和 end() 成员方法,C++ STL 标准库中还提供有同名且具有相同功能的begin() 和 end() 函数。 首先需要说明的是,begin() 和 end() 是以函数模板的形式定义的,但它们的模板并没有位于某一个头文件中,而是很多头文件中都有它们的定义。 C++ STL 标准库中,包含 begin() 和 end() 函数模板的头文件包括:... c.begin()形式:返回指向容器首元素的iterator;begin(array)或begin(c)形式:返回数组的头指针。c.end()形式:返回指向紧挨尾元素的元素的iterator;end(array)或end(c)形式:返回紧挨数组尾指针的指针。说明:对于end函数来说,给定范围的“终止点”并不包含在给定范围内,而是紧挨着范围内最后一个可用元素的元素。c: 包括begin成员函数/end成员函数的容器;array: 任意类型的数组。 在一个软件项目中,如果需要在一个文件中包含另一个头文件时,一般有两种包含方式:#include <stdio.h> #include “module.h”如果你引用的头文件是标准库的头文件或官方路径下的头文件,一般使用尖括号<>包含;如果你使用的头文件是自定义的或项目中的头文件,一般使用双引号""包含。头文件路径一般分为绝对路径和相对路径:绝对路径以根目录/或者Window...