c/c++开发,无可避免的模板编程实践(篇九)-c++11的新顺序容器
创始人
2024-05-31 15:33:25
0

一、std::array数组容器

        1.1 数组的适配器-std::array

        std::array 是封装固定大小数组的容器,是c++11标准库新引入的顺序容器,定义于头文件

template  struct array; 

        此容器是一个聚合类型,其语义等同于保有一个 C 风格数组 T[N] 的结构体。不同于 C 风格数组,它不会自动退化成 T* 。它在定义时,需要显式指定模板参数类型和非模板参数数值,它能作为聚合类型聚合初始化,只要有至多 N 个能转换成 T 的初始化器,可将 array 当做拥有 N 个同类型元素的元组:

 std::array a = {1,2,3}; 

        std::array 满足容器 (Container) 和可逆容器 (ReversibleContainer) 的要求,除了默认构造的 array 是非空的,以及进行交换的复杂度是线性,它满足连续容器 (ContiguousContainer) (C++17 起)的要求并部分满足序列容器 (SequenceContainer) 的要求。

         还记得在本课题的篇一的“3.4 非类型模板参数及缺省值”中讲述结构体模板内容:

#define RDC_SIZE 1024	//服务端从socket读取数据时的缓存大小
#define DATA_SIZE 512	//服务及客户端的数据传输(读取及写入)的缓存大小template
struct TCP_Data
{TCP_Data() : len(0){memset(Buf,0,SIZE);};...省略其他...unsigned char Buf[SIZE];int len;
};

        现在将他改造成一个类似std::array结构体,及数组类型为T,长度为SIZE:

#include 
#include template
struct my_array
{my_array() {memset(Buf,0,SIZE);};~my_array(){};T& operator[]( const int pos ){assert(pos >= 0 && pos < SIZE);return Buf[pos];}T& at(const int pos){assert(pos >= 0 && pos < SIZE);return Buf[pos];}//其他实现T Buf[SIZE];
};void myarray_test(void)
{//调用my_array a;          //int类型数据,长度大小3a[0] = 9;a.at(1) = 10;std::cout << "a.at(0)=" << a.at(0) << "\n";std::cout << "a[1]=" << a[1] << "\n";
};

        这就是std::array容器内部的数据组织结构,通过可以说它就是一个数组适配器,在一个数组存储结构基础上,提供了元素访问、迭代器、容量、操作符等功能函数以及构造、析构、赋值等类成员。当然,除了上述一下成员及成员函数以为,标准库还std::array容器类模板提供了一些辅助函数、比较函数等。

        1.2 认识std::array容器(c++11起)

        std::array容器本质上是一个结构体模板,它结合了 C 风格数组的性能、可访问性与容器的优点,比如可获取大小、支持赋值、随机访问迭代器等。其功能函数如下:

成员类型                     定义 
value_type                   T 
size_type                    std::size_t 
difference_type              std::ptrdiff_t 
reference                    value_type& 
const_reference              const value_type& 
pointer                      value_type* 
const_pointer                const value_type* 
iterator//->
/*
[1]指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator)  
[2]指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 且为字面类型 (LiteralType) (C++20 前) 
[3]指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) (C++20 起) 
*/
const_iterator//-> 
/*
[1]指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator)
[2]指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 且为字面类型 (LiteralType) (C++20 前) 
[3]指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) (C++20 起) 
*/
reverse_iterator               std::reverse_iterator 
const_reverse_iterator         std::reverse_iterator 成员函数
(构造函数)    //(隐式声明)遵循聚合初始化的规则初始化array(注意默认初始化可以导致非类的T的不确定值)(公开成员函数) 
(析构函数)    //(隐式声明) 销毁 array 的每个元素(公开成员函数) 
operator=    //(隐式声明)以来自另一 array 的每个元素重写 array 的对应元素(公开成员函数) 元素访问
at           //(C++11) 访问指定的元素,同时进行越界检查(公开成员函数) 
operator[]   //(C++11) 访问指定的元素(公开成员函数) 
front        //(C++11) 访问第一个元素(公开成员函数) 
back         //(C++11) 访问最后一个元素(公开成员函数) 
data         //(C++11) 直接访问底层数组(公开成员函数) 迭代器
begin        //(C++11)返回指向起始的迭代器(公开成员函数) 
cbegin       //(C++11)返回指向起始的迭代器(公开成员函数) 
end          //(C++11)返回指向末尾的迭代器(公开成员函数) 
cend         //(C++11)返回指向末尾的迭代器(公开成员函数) rbegin       //(C++11)返回指向起始的逆向迭代器(公开成员函数) 
crbegin      //(C++11)返回指向起始的逆向迭代器(公开成员函数) rend         //(C++11)返回指向末尾的逆向迭代器(公开成员函数) 
crend        //(C++11)返回指向末尾的逆向迭代器(公开成员函数) 容量
empty        //(C++11) 检查容器是否为空(公开成员函数) 
size         //(C++11) 返回容纳的元素数(公开成员函数) 
max_size     //(C++11) 返回可容纳的最大元素数(公开成员函数) 操作
fill         //(C++11) 以指定值填充容器(公开成员函数) 
swap         //(C++11) 交换内容(公开成员函数) 非成员函数
operator==    //按照字典顺序比较 array 中的值(函数模板)
operator!=    //(C++20 中移除)
operator<     //(C++20 中移除)
operator<=    //(C++20 中移除)
operator>     //(C++20 中移除)
operator>=    //(C++20 中移除)       
operator<=>   //(C++20) std::get(std::array)  //访问 array 的一个元素(函数模板) 
std::swap(std::array) //(C++11)特化 std::swap 算法(函数模板) 
to_array              //(C++20)从内建数组创建 std::array 对象(函数模板) 辅助类
std::tuple_size    //(C++11)获得 array 的大小(类模板特化) 
std::tuple_element //(C++11)获得 array 元素的类型(类模板特化)

        std::array容器定义在标准库头文件 中,本质上就是一个包含模板参数T和非模板参数size_t的结构体,放置在std命名空间内:

namespace std {templatestruct array {// 类型using value_type             = T;using pointer                = T*;using const_pointer          = const T*;using reference              = T&;using const_reference        = const T&;using size_type              = size_t;using difference_type        = ptrdiff_t;using iterator               = /* 由实现定义 */;using const_iterator         = /* 由实现定义 */;using reverse_iterator       = std::reverse_iterator;using const_reverse_iterator = std::reverse_iterator;// 聚合类型无显式的构造/复制/销毁constexpr void fill(const T& u);constexpr void swap(array&) noexcept(is_nothrow_swappable_v);// 迭代器constexpr iterator               begin() noexcept;constexpr const_iterator         begin() const noexcept;constexpr iterator               end() noexcept;constexpr const_iterator         end() const noexcept;constexpr reverse_iterator       rbegin() noexcept;constexpr const_reverse_iterator rbegin() const noexcept;constexpr reverse_iterator       rend() noexcept;constexpr const_reverse_iterator rend() const noexcept;constexpr const_iterator         cbegin() const noexcept;constexpr const_iterator         cend() const noexcept;constexpr const_reverse_iterator crbegin() const noexcept;constexpr const_reverse_iterator crend() const noexcept;// 容量[[nodiscard]] constexpr bool empty() const noexcept;constexpr size_type size() const noexcept;constexpr size_type max_size() const noexcept;// 元素访问constexpr reference       operator[](size_type n);constexpr const_reference operator[](size_type n) const;constexpr reference       at(size_type n);constexpr const_reference at(size_type n) const;constexpr reference       front();constexpr const_reference front() const;constexpr reference       back();constexpr const_reference back() const;constexpr T *       data() noexcept;constexpr const T * data() const noexcept;};templatearray(T, U...) -> array;
}

        前面也讲述到std::array类模板能作为聚合类型聚合初始化:

void construct_test(void)
{// 用聚合初始化构造std::array a1{ {1, 2, 3} }; // CWG 1270 前的 C++11 中要求双花括号// ( C++11 之后的版本和 C++14 起不要求)std::array a2 = {1, 2, 3};  // = 后决不要求双花括号std::array a3 = { std::string("a"), "b" };// 支持容器操作std::sort(a1.begin(), a1.end());std::reverse_copy(a2.begin(), a2.end(), std::ostream_iterator(std::cout, " "));std::cout << '\n';// 支持带范围 for 循环for(const auto& s: a3)std::cout << s << ' ';std::cout << '\n';
};

        1.3 std::array容器使用

        该类模板也和其他顺序容器一样,提供了下标访问、at访问、front访问、back访问等元素访问方式,在零长 array 上调用 front() 或 back() 是未定义的:

void getval_test(void)
{std::array data = { 1, 2, 4, 5, 5, 6 };// Set element 1data.at(1) = 88;// Read element 2std::cout << "Element at index 2 has value " << data.at(2) << '\n';std::cout << "data size = " << data.size() << '\n';try {// Set element 6data.at(6) = 666;} catch (std::out_of_range const& exc) {std::cout << exc.what() << '\n';}// Print final valuesstd::cout << "data:";for (int elem : data)std::cout << " " << elem;std::cout << '\n';//std::array letters {'o', 'm', 'g', 'w', 't', 'f'};if (!letters.empty()) {std::cout << "The last character is: " << letters.back() << '\n';} 
};

        同时,与数组结构最大的区别就是提供了正向和逆向的迭代器支持,当其长度为零时 array ( N == 0 )有特殊情况。此时, array.begin() == array.end() ,并拥有某个唯一值:

void iterator_test_array(void)
{std::cout << std::boolalpha;std::array empty;std::cout << "1) "<< (empty.begin() == empty.end()) << ' '     // true<< (empty.cbegin() == empty.cend()) << '\n'; // true// *(empty.begin()) = 42; // => 运行时的未定义行为std::array numbers{5, 2, 3, 4};std::cout << "2) "<< (numbers.begin() == numbers.end()) << ' '    // false<< (numbers.cbegin() == numbers.cend()) << '\n' // false<< "3) "<< *(numbers.begin()) << ' '    // 5<< *(numbers.cbegin()) << '\n'; // 5*numbers.begin() = 1;std::cout << "4) " << *(numbers.begin()) << '\n'; // 1// *(numbers.cbegin()) = 42; // 编译时错误:// 只读变量不可赋值// 打印所有元素std::cout << "5) ";std::for_each(numbers.cbegin(), numbers.cend(), [](int x) {std::cout << x << ' ';});std::cout << '\n';#if(__cplusplus>=201703L)//c++17constexpr std::array arrs{'A', 'B', 'C'};static_assert(arrs.begin() != arrs.end());   // OKstatic_assert(arrs.cbegin() != arrs.cend()); // OKstatic_assert(*arrs.begin() == 'A');              // OKstatic_assert(*arrs.cbegin() == 'A');             // OK// *arrs.begin() = 'Z'; // 编译时错误:只读变量不可赋值#endif
};

        下来我们验证一下std::array容器与同等大小的数组的效率问题,数组的功能有限,我们只通过对元素赋值操作演示:

#include 
#include 
#include 
#include 
#include void speed_test(void)
{const unsigned long sizel = 100000;//不能设值太大,数组分配会有问题int vec_test[sizel] = {0};std::array arr_test{0};auto start = std::chrono::system_clock::now();for(int row=0; row<100; row++){for (size_t i = 0; i < sizel; i++){vec_test[i] =(rand()/sizel);}}auto end = std::chrono::system_clock::now();std::chrono::duration diff = end-start;std::cout << "vec_test diff.count() = " <<  diff.count() << "ms\n";start = std::chrono::system_clock::now();for(int row=0; row<100; row++){for (size_t i = 0; i < sizel; i++){arr_test[i] =(rand()/sizel);}}end = std::chrono::system_clock::now();diff = end-start;std::cout << "arr_test diff.count() = " <<  diff.count() << "ms\n";start = std::chrono::system_clock::now();std::array::iterator iter = arr_test.begin();for(int row=0; row<100; row++){for (iter = arr_test.begin(); iter!=arr_test.end(); iter++){*iter = (rand()/sizel);}}end = std::chrono::system_clock::now();diff = end-start;std::cout << "arr_test iterator diff.count() = " <<  diff.count() << "ms\n";
};

        编译测试比较示例,程序输出如下,可以看到执行100*100000的元素随机赋值,std::array也能维持和纯数组在毫秒级内,缺带来正反迭代器、边界检查、容量检查等扩展:

二、std::forward_list-单链表

        2.1 认识std::forward_list容器

        std::forward_list容器是c++11标准新增的顺序容器,是支持从容器中的任何位置快速插入和移除元素的容器。与 std::list 相比,它实现为单链表,此容器在不需要双向迭代时提供更有效地利用空间的存储。该容器定义于头文件 中。

template< class T, class Allocator = std::allocator >
class forward_list;                                                 //(C++11 起) namespace pmr { template  using forward_list = std::forward_list >       // (C++17 起) 
} 

        std::forward_list容器是一个类模板,T - 元素的类型,其需要支持到容器的实际操作,如比较、赋值等;模板参数 Allocator - 用于获取/释放内存及构造/析构内存中元素的分配器。类型必须满足分配器 (Allocator) 的要求。若 Allocator::value_type 与 T 不同则行为未定义 (C++20 前)程序非良构 (C++20 起)。std::forward_list 满足容器 (Container) (除了 operator== 的复杂度始终为线性和 size 函数)、知分配器容器 (AllocatorAwareContainer) 和序列容器 (SequenceContainer) 的要求。

        std::forward_list定义对象实例时,需要显式指明元素类型,支持从各种数据源构造新容器,可选地使用用户提供的分配器 alloc

/*默认构造函数。构造拥有默认构造的分配器的空容器*/
forward_list();                                     //空表 
/*构造拥有给定分配器 alloc 的空容器,
*alloc-用于此容器所有内存分配的分配器 */
explicit forward_list( const Allocator& alloc );    //指定分配器  
/*构造拥有 count 个有值 value 的元素的容器。
*count - 容器的大小 ,value - 以之初始化容器元素的值 */
forward_list( size_type count, const T& value,const Allocator& alloc = Allocator()); //(C++11 起)
/*构造拥有个 count 默认插入的 T 实例的容器。不进行复制*/
explicit forward_list(size_type count);              //(C++11 起)(C++14 前) 
explicit forward_list(size_type count, const Allocator& alloc = Allocator());//(C++14 起) 
/*构造拥有范围 [first, last) 内容的容器
*first, last - 复制元素的来源范围 */
template< class InputIt > 
forward_list( InputIt first, InputIt last,const Allocator& alloc = Allocator() );              //(C++11 起) 
/*复制构造函数。构造拥有 other 内容的容器
*other - 用作初始化容器元素来源的另一容器 */
forward_list( const forward_list& other );                         //(C++11 起) 
/*构造拥有 other 内容的容器,以 alloc 为分配器*/
forward_list( const forward_list& other, const Allocator& alloc ); //(C++11 起) 
/* 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得*/
forward_list( forward_list&& other );                              //(C++11 起) 
/*有分配器扩展的移动构造函数。以 alloc 为新容器的分配器,从 other 移动内容;若 alloc != other.get_allocator() ,则它导致逐元素移动*/
forward_list( forward_list&& other, const Allocator& alloc );      //(C++11 起)
/*构造拥有 initializer_list init 内容的容器
*init - 用作初始化元素来源的 initializer_list */
forward_list( std::initializer_list init,const Allocator& alloc = Allocator() );             //(C++11 起) 

        std::forward_list提供了多种构造方式定义对象实例,满足不同业务场景需要:

#include 
#include 
#include template
std::ostream& operator<<(std::ostream& s, const std::forward_list& v)
{s.put('[');char comma[3] = {'\0', ' ', '\0'};for (const auto& e : v) {s << comma << e;comma[0] = ',';}return s << ']';
};void construction_test(void)
{// C++11 初始化器列表语法:std::forward_list words1 {"the", "frogurt", "is", "also", "cursed"};std::cout << "words1: " << words1 << '\n';// words2 == words1std::forward_list words2(words1.begin(), words1.end());std::cout << "words2: " << words2 << '\n';// words3 == words1std::forward_list words3(words1);std::cout << "words3: " << words3 << '\n';// words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}std::forward_list words4(5, "Mo");std::cout << "words4: " << words4 << '\n';    
};

        可以通过=操作符赋值给容器,也可以assign将值赋给容器

void assign_test(void)
{std::forward_list l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };for (int c : l) {std::cout << c << ' ';}std::forward_list characters;characters.assign(5, 'a');for (char c : characters) {std::cout << c << ' ';} characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});for (char c : characters) {std::cout << c;}
};

        2.2 std::forward_list容器使用

        std::forward_list提供了元素访问、迭代器、修改器、操作符等成员变量,也提供比较、删除、交换元素的辅助函数模板,其大体上和双链表std::list差不多:

成员类型                     定义 
value_type                   T 
allocator_type               Allocator 
size_type                    无符号整数类型(通常是 std::size_t ) 
difference_type              有符号整数类型(通常是 std::ptrdiff_t ) 
reference                    value_type& 
const_reference              const value_type& 
pointer                      std::allocator_traits::pointer 
const_pointer                std::allocator_traits::const_pointer 
iterator                     指向 value_type 的常老式向前迭代器 (LegacyForwardIterator) 
const_iterator               指向 const value_type 的老式向前迭代器 (LegacyForwardIterator) 成员函数
(构造函数)                (C++11)  构造 forward_list(公开成员函数) 
(析构函数)                (C++11)  析构 forward_list(公开成员函数) 
operator=                (C++11)  赋值给容器(公开成员函数) 
assign                   (C++11)  将值赋给容器(公开成员函数) 
get_allocator            (C++11)返回相关的分配器 (公开成员函数) 元素访问
front (C++11)  访问第一个元素(公开成员函数) 迭代器
before_begin          (C++11)  返回指向第一个元素之前迭代器(公开成员函数) 
cbefore_beginbegin                 (C++11) 返回指向起始的迭代器(公开成员函数) 
cbeginend                   (C++11) 返回指向末尾的迭代器(公开成员函数) 
cend容量
empty                 (C++11) 检查容器是否为空(公开成员函数) 
max_size              (C++11) 返回可容纳的最大元素数(公开成员函数) 修改器
clear                 (C++11) 清除内容(公开成员函数) 
insert_after          (C++11) 在某个元素后插入新元素(公开成员函数) 
emplace_after         (C++11) 在元素后原位构造元素(公开成员函数) 
erase_after           (C++11) 擦除元素后的元素(公开成员函数) 
push_front            (C++11) 插入元素到容器起始(公开成员函数) 
emplace_front         (C++11) 在容器头部原位构造元素(公开成员函数) 
pop_front             (C++11) 移除首元素(公开成员函数) 
resize                (C++11) 改变容器中可存储元素的个数(公开成员函数) 
swap                  (C++11) 交换内容(公开成员函数) 操作
merge                 (C++11) 合并二个已排序列表(公开成员函数) 
splice_after          (C++11) 从另一 forward_list 移动元素(公开成员函数) 
removeremove_if       (C++11) 移除满足特定标准的元素(公开成员函数) 
reverse               (C++11) 将该链表的所有元素的顺序反转(公开成员函数) 
unique                (C++11) 删除连续的重复元素(公开成员函数) 
sort                  (C++11) 对元素进行排序(公开成员函数) 非成员函数
operator==        按照字典顺序比较 forward_list 中的值(函数模板) 
operator!=        (C++20 中移除)
operator<         (C++20 中移除)
operator<=        (C++20 中移除)    
operator>         (C++20 中移除)
operator>=        (C++20 中移除)
operator<=>       (C++20)std::swap(std::forward_list)    (C++11)  特化 std::swap 算法(函数模板) 
erase(std::forward_list)        (C++20) 擦除所有满足特定判别标准的元素(函数模板) 
erase_if(std::forward_list) 

         std::forward_list容器是不支持快速随机访问的单链表,定义在标准库头文件 中,本质上就是一个包含模板参数T和另一个模板参数std::allocator 类模板,放置在std命名空间内:

namespace std {template>class forward_list {public:// 类型using value_type      = T;using allocator_type  = Allocator;using pointer         = typename allocator_traits::pointer;using const_pointer   = typename allocator_traits::const_pointer;using reference       = value_type&;using const_reference = const value_type&;using size_type       = /* 由实现定义 */;using difference_type = /* 由实现定义 */;using iterator        = /* 由实现定义 */;using const_iterator  = /* 由实现定义 */;// 构造/复制/销毁forward_list() : forward_list(Allocator()) { }explicit forward_list(const Allocator&);explicit forward_list(size_type n, const Allocator& = Allocator());forward_list(size_type n, const T& value, const Allocator& = Allocator());templateforward_list(InputIt first, InputIt last, const Allocator& = Allocator());forward_list(const forward_list& x);forward_list(forward_list&& x);forward_list(const forward_list& x, const Allocator&);forward_list(forward_list&& x, const Allocator&);forward_list(initializer_list, const Allocator& = Allocator());~forward_list();forward_list& operator=(const forward_list& x);forward_list& operator=(forward_list&& x)noexcept(allocator_traits::is_always_equal::value);forward_list& operator=(initializer_list);templatevoid assign(InputIt first, InputIt last);void assign(size_type n, const T& t);void assign(initializer_list);allocator_type get_allocator() const noexcept;// 迭代器iterator before_begin() noexcept;const_iterator before_begin() const noexcept;iterator begin() noexcept;const_iterator begin() const noexcept;iterator end() noexcept;const_iterator end() const noexcept;const_iterator cbegin() const noexcept;const_iterator cbefore_begin() const noexcept;const_iterator cend() const noexcept;// 容量[[nodiscard]] bool empty() const noexcept;size_type max_size() const noexcept;// 元素访问reference front();const_reference front() const;// 修改器template reference emplace_front(Args&&... args);void push_front(const T& x);void push_front(T&& x);void pop_front();templateiterator emplace_after(const_iterator position, Args&&... args);iterator insert_after(const_iterator position, const T& x);iterator insert_after(const_iterator position, T&& x);iterator insert_after(const_iterator position, size_type n, const T& x);templateiterator insert_after(const_iterator position, InputIt first, InputIt last);iterator insert_after(const_iterator position, initializer_list il);iterator erase_after(const_iterator position);iterator erase_after(const_iterator position, const_iterator last);void swap(forward_list&)noexcept(allocator_traits::is_always_equal::value);void resize(size_type sz);void resize(size_type sz, const value_type& c);void clear() noexcept;// forward_­list 操作void splice_after(const_iterator position, forward_list& x);void splice_after(const_iterator position, forward_list&& x);void splice_after(const_iterator position, forward_list& x, const_iterator i);void splice_after(const_iterator position, forward_list&& x, const_iterator i);void splice_after(const_iterator position, forward_list& x,const_iterator first, const_iterator last);void splice_after(const_iterator position, forward_list&& x,const_iterator first, const_iterator last);size_type remove(const T& value);template size_type remove_if(Predicate pred);size_type unique();template size_type unique(BinaryPredicate binary_pred);void merge(forward_list& x);void merge(forward_list&& x);template void merge(forward_list& x, Compare comp);template void merge(forward_list&& x, Compare comp);void sort();template void sort(Compare comp);void reverse() noexcept;};template>>forward_list(InputIt, InputIt, Allocator = Allocator())-> forward_list, Allocator>;// 交换templatevoid swap(forward_list& x, forward_list& y)noexcept(noexcept(x.swap(y)));
}

        std::allocator 类模板定义于头文件 ,是所有标准库容器所用的默认分配器 (Allocator) ,若不提供用户指定的分配器。默认分配器无状态,即任何给定的 allocator 实例可交换、比较相等,且能解分配同一 allocator 类型的任何其他实例所分配的内存。


template< class T > struct allocator;
template<> struct allocator; //(C++17 中弃用)(C++20 中移除) 

        std::forward_list容器和其他容器一样支持iterator,通过迭代器可以实现容器遍历及元素访问:

void iterator_test(void)
{//std::forward_list nums {1, 2, 4, 8, 16};auto print = [](const int& n) { std::cout << " " << n; };std::cout << "Before for_each:";std::for_each(nums.begin(), nums.end(), print);std::cout << '\n';//out:Before for_each: 1 2 4 8 16std::forward_list fruits {"orange", "apple", "raspberry"};std::forward_list empty;// 求和 forward_list nums 中的所有整数(若存在),仅打印结果。std::cout << "Sum of nums: " <

        容器支持数据插入、删除操作,在链表内或跨数个链表添加、移除和移动元素,不会非法化当前指代链表中其他元素的迭代器。然而,在从链表移除元素(通过 erase_after )时,指代对应元素的迭代器或引用会被非法化。

void modify_test(void)
{std::forward_list l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };l.push_front(0);    //元素 value 到容器起始l.emplace_front(0); //插入新元素到容器起始。l.insert_after(l.begin(),10);         //在容器中的指定位置后插入元素。l.emplace_after(l.before_begin(),100);//在容器中的指定位置后插入新元素。for (int c : l) {std::cout << c << ' ';}std::cout << '\n';//out: 100 0 10 0 1 2 3 4 5 6 7 8 9//    l.erase( l.begin() ); // 错误:无要擦除的元素l.erase_after( l.before_begin() ); // 移除首元素l.pop_front();for( auto n : l ) {std::cout << n << " ";}std::cout << '\n';//out: 10 0 1 2 3 4 5 6 7 8 9auto fi= std::next( l.begin() );auto la= std::next( fi, 3 );l.erase_after( fi, la );for( auto n : l ) std::cout << n << " ";std::cout << '\n';  //out: 10 0 3 4 5 6 7 8 9//clearauto print = [](const int& n) { std::cout << " " << n; };std::cout << "Before clear:";std::for_each(l.begin(), l.end(), print);std::cout << '\n';//out: Before clear: 10 0 3 4 5 6 7 8 9std::cout << "Clear\n";l.clear();std::cout << "After clear:";std::for_each(l.begin(), l.end(), print);std::cout << '\n';//out: After clear:
};

        更多的成员还是用法就不一一展示了,大部分用法都可以参考std::list的用法,除了不支持逆序迭代外。

相关内容

热门资讯

开晨会需要说什么内容 开晨会需要说什么内容晨会说的内容可以很多呀,可以说接下来的工作安排,也可以说,前期工作中的一些总结,...
有谁知道在鬼吹灯有声小说中前面... 有谁知道在鬼吹灯有声小说中前面有一段小女孩的声音念:人点烛 鬼吹灯... 这个版本的故事是谁讲的?周...
小蒂皮出自哪本书 小蒂皮出自哪本书小蒂皮出自哪本书我的野生动物朋友(蒂皮·本杰明·奥康迪·德格雷著图书)《我的野生动物...
盘古开天辟地的故事 盘古开天辟地的故事很久很久以前,天和地还没有分开,宇宙混沌一片。有个叫盘古的巨人一直睡在这混沌之中。...
英雄联盟中 赏金猎人怎么样? ... 英雄联盟中 赏金猎人怎么样? 多少钱 金币3150的ADC。入手的话不会吃亏,基本不会压箱底,很热门...
寻找一部累死何以笙箫默之类的小... 寻找一部累死何以笙箫默之类的小说也是辛夷坞的,叫山月不知心底事那就它的作者顾漫的其他小说呗 微微一...
大家谈谈对洪荒小说之中圣人的看... 大家谈谈对洪荒小说之中圣人的看法圣人不死,大盗不止都是人 人有的情绪他们都有 就是拳头大些对...
单位体检,自己一个人去害怕撞到... 单位体检,自己一个人去害怕撞到同事怎么办,不想别人看到观察我,漏出我不成熟样子,显出我的丑态。这让单...
鱼在天上飞? 鱼在天上飞?“鱼在天上飞,鸟在水里游”这句话的意思是鸟儿在水中的倒影就像是在水里游,天空在水中的倒影...
我想复婚,前夫说以后再,我改变... 我想复婚,前夫说以后再,我改变好了,他有可能追我,现在不想复婚,他有喜欢的女人了,我们就不可能了吗感...
原神草神什么时候复刻 原神草神什么时候复刻原神草神复刻是在3.6版本以后。草神纳西妲首次登场是逗腊3.2版本,新角色想要等...
网络拽姐语录小学生? 网络拽姐语录小学生?无论谁离开了你,请你别忘了,他没来之前,你本就是一个人生活。
有一部小说,女主小时候被男主收... 有一部小说,女主小时候被男主收养了,女主叫男主哥哥,男主对女主的我也在找这个小说我之前也看了,好像叫...
高层建筑立面大面积粉刷需要设伸... 高层建筑立面大面积粉刷需要设伸缩缝吗?高层建筑立面大面积粉刷需要设伸缩缝需要的,无正举论地面或立念清...
低头思故乡,为什么把杯思在长,... 低头思故乡,为什么把杯思在长,情愿何处在方歌曲叫什么名字“李白的歌”离开了家乡 背着沉沉的行囊开始了...
李白的诗有多少 李白的诗有多少典故中大多说是三千至四千首,现存不足一千首很多,总之不少~李白一生留下了九百六十多首诗...
怎么才可以学会拿得起放得下……... 怎么才可以学会拿得起放得下…… 有一段感情,正整3年了,可是我还是觉得分手那天就好像昨天发生的一样替...
为什么官方直播间买手机送耳机 为什么官方直播间买手机送耳机吸引消费者,增加销售量。官方直播间作为官方的直播平台,买手机送耳机是为了...
自考通还是一考通好?该选哪个? 自考通还是一考通好?该选哪个?我现在自考行政管理专科。专业课程我应该选自考通好还是一考通好呢?这个很...
淘宝实际付款价格为什么与订单价... 淘宝实际付款价格为什么与订单价格不符是这样的,我买了一双鞋,当时限价160我拍了下来,当时没付款,后...