一、std::array数组容器
1.1 数组的适配器-std::array
std::array
是封装固定大小数组的容器,是c++11标准库新引入的顺序容器,定义于头文件 <array>。
template <class T,std::size_t N > struct array;
此容器是一个聚合类型,其语义等同于保有一个 C 风格数组 T[N] 的结构体。不同于 C 风格数组,它不会自动退化成 T* 。它在定义时,需要显式指定模板参数类型和非模板参数数值,它能作为聚合类型聚合初始化,只要有至多 N 个能转换成 T 的初始化器,可将 array 当做拥有 N 个同类型元素的元组:
std::array<int, 3> 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<int SIZE = DATA_SIZE>
struct TCP_Data
{
TCP_Data()
: len(0)
{
memset(Buf,0,SIZE);
};
...省略其他...
unsigned char Buf[SIZE];
int len;
};
现在将他改造成一个类似std::array结构体,及数组类型为T,长度为SIZE:
#include <cstring>
#include <cassert>
template<typename T,int SIZE>
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<int,3> a; //int类型数据,长度大小3
a[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<iterator>
const_reverse_iterator std::reverse_iterator<const_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<std::array> //(C++11)获得 array 的大小(类模板特化)
std::tuple_element<std::array> //(C++11)获得 array 元素的类型(类模板特化)
std::array容器定义在标准库头文件 <array>中,本质上就是一个包含模板参数T和非模板参数size_t的结构体,放置在std命名空间内:
namespace std {
template<class T, size_t N>
struct 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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// 聚合类型无显式的构造/复制/销毁
constexpr void fill(const T& u);
constexpr void swap(array&) noexcept(is_nothrow_swappable_v<T>);
// 迭代器
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;
};
template<class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
}
前面也讲述到std::array类模板能作为聚合类型聚合初始化:
void construct_test(void)
{
// 用聚合初始化构造
std::array<int, 3> a1{ {1, 2, 3} }; // CWG 1270 前的 C++11 中要求双花括号
// ( C++11 之后的版本和 C++14 起不要求)
std::array<int, 3> a2 = {1, 2, 3}; // = 后决不要求双花括号
std::array<std::string, 2> a3 = { std::string("a"), "b" };
// 支持容器操作
std::sort(a1.begin(), a1.end());
std::reverse_copy(a2.begin(), a2.end(),
std::ostream_iterator<int>(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<int,6> data = { 1, 2, 4, 5, 5, 6 };
// Set element 1
data.at(1) = 88;
// Read element 2
std::cout << "Element at index 2 has value " << data.at(2) << '\n';
std::cout << "data size = " << data.size() << '\n';
try {
// Set element 6
data.at(6) = 666;
} catch (std::out_of_range const& exc) {
std::cout << exc.what() << '\n';
}
// Print final values
std::cout << "data:";
for (int elem : data)
std::cout << " " << elem;
std::cout << '\n';
//
std::array<char, 6> 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<int, 0> empty;
std::cout << "1) "
<< (empty.begin() == empty.end()) << ' ' // true
<< (empty.cbegin() == empty.cend()) << '\n'; // true
// *(empty.begin()) = 42; // => 运行时的未定义行为
std::array<int, 4> 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++17
constexpr std::array<char,3> arrs{'A', 'B', 'C'};
static_assert(arrs.begin() != arrs.end()); // OK
static_assert(arrs.cbegin() != arrs.cend()); // OK
static_assert(*arrs.begin() == 'A'); // OK
static_assert(*arrs.cbegin() == 'A'); // OK
// *arrs.begin() = 'Z'; // 编译时错误:只读变量不可赋值
#endif
};
下来我们验证一下std::array容器与同等大小的数组的效率问题,数组的功能有限,我们只通过对元素赋值操作演示:
#include <chrono>
#include <random>
#include <iterator>
#include <iostream>
#include <array>
void speed_test(void)
{
const unsigned long sizel = 100000;//不能设值太大,数组分配会有问题
int vec_test[sizel] = {0};
std::array<int, sizel> 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<double,std::milli> 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<int, sizel>::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 相比,它实现为单链表,此容器在不需要双向迭代时提供更有效地利用空间的存储。该容器定义于头文件 <forward_list>中。
template< class T, class Allocator = std::allocator<T> >
class forward_list; //(C++11 起)
namespace pmr {
template <class T> using forward_list =
std::forward_list<T, std::pmr::polymorphic_allocator<T> > // (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<T> init,
const Allocator& alloc = Allocator() ); //(C++11 起)
std::forward_list提供了多种构造方式定义对象实例,满足不同业务场景需要:
#include <iostream>
#include <string>
#include <forward_list>
template<typename T>
std::ostream& operator<<(std::ostream& s, const std::forward_list<T>& 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<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
std::cout << "words1: " << words1 << '\n';
// words2 == words1
std::forward_list<std::string> words2(words1.begin(), words1.end());
std::cout << "words2: " << words2 << '\n';
// words3 == words1
std::forward_list<std::string> words3(words1);
std::cout << "words3: " << words3 << '\n';
// words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
std::forward_list<std::string> words4(5, "Mo");
std::cout << "words4: " << words4 << '\n';
};
可以通过=操作符赋值给容器,也可以assign将值赋给容器
void assign_test(void)
{
std::forward_list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int c : l) {
std::cout << c << ' ';
}
std::forward_list<char> 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<Allocator>::pointer
const_pointer std::allocator_traits<Allocator>::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_begin
begin (C++11) 返回指向起始的迭代器(公开成员函数)
cbegin
end (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容器是不支持快速随机访问的单链表,定义在标准库头文件 <forward_list>中,本质上就是一个包含模板参数T和另一个模板参数std::allocator<T>
类模板,放置在std命名空间内:
namespace std {
template<class T, class Allocator = allocator<T>>
class forward_list {
public:
// 类型
using value_type = T;
using allocator_type = Allocator;
using pointer = typename allocator_traits<Allocator>::pointer;
using const_pointer = typename allocator_traits<Allocator>::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());
template<class InputIt>
forward_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<T>, const Allocator& = Allocator());
~forward_list();
forward_list& operator=(const forward_list& x);
forward_list& operator=(forward_list&& x)
noexcept(allocator_traits<Allocator>::is_always_equal::value);
forward_list& operator=(initializer_list<T>);
template<class InputIt>
void assign(InputIt first, InputIt last);
void assign(size_type n, const T& t);
void assign(initializer_list<T>);
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<class... Args> reference emplace_front(Args&&... args);
void push_front(const T& x);
void push_front(T&& x);
void pop_front();
template<class... Args>
iterator 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);
template<class InputIt>
iterator insert_after(const_iterator position, InputIt first, InputIt last);
iterator insert_after(const_iterator position, initializer_list<T> il);
iterator erase_after(const_iterator position);
iterator erase_after(const_iterator position, const_iterator last);
void swap(forward_list&)
noexcept(allocator_traits<Allocator>::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<class Predicate> size_type remove_if(Predicate pred);
size_type unique();
template<class BinaryPredicate> size_type unique(BinaryPredicate binary_pred);
void merge(forward_list& x);
void merge(forward_list&& x);
template<class Compare> void merge(forward_list& x, Compare comp);
template<class Compare> void merge(forward_list&& x, Compare comp);
void sort();
template<class Compare> void sort(Compare comp);
void reverse() noexcept;
};
template<class InputIt, class Allocator = allocator</*iter-value-type*/<InputIt>>>
forward_list(InputIt, InputIt, Allocator = Allocator())
-> forward_list</*iter-value-type*/<InputIt>, Allocator>;
// 交换
template<class T, class Allocator>
void swap(forward_list<T, Allocator>& x, forward_list<T, Allocator>& y)
noexcept(noexcept(x.swap(y)));
}
std::allocator 类模板定义于头文件 <memory>,是所有标准库容器所用的默认分配器 (Allocator) ,若不提供用户指定的分配器。默认分配器无状态,即任何给定的 allocator 实例可交换、比较相等,且能解分配同一 allocator 类型的任何其他实例所分配的内存。
template< class T > struct allocator;
template<> struct allocator<void>; //(C++17 中弃用)(C++20 中移除)
std::forward_list容器和其他容器一样支持iterator,通过迭代器可以实现容器遍历及元素访问:
void iterator_test(void)
{
//
std::forward_list<int> 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 16
std::forward_list<std::string> fruits {"orange", "apple", "raspberry"};
std::forward_list<char> empty;
// 求和 forward_list nums 中的所有整数(若存在),仅打印结果。
std::cout << "Sum of nums: " <<
std::accumulate(nums.begin(), nums.end(), 0) << "\n";
//out:Sum of nums: 31
// 打印 forward_list fruits 中的首个 fruis ,不检查是否有一个。
std::cout << "First fruit: " << *fruits.begin() << "\n"; //First fruit: orange
if (empty.begin() == empty.end())
std::cout << "forward_list 'empty' is indeed empty.\n"; //forward_list 'empty' is indeed empty.
};
容器支持数据插入、删除操作,在链表内或跨数个链表添加、移除和移动元素,不会非法化当前指代链表中其他元素的迭代器。然而,在从链表移除元素(通过 erase_after )时,指代对应元素的迭代器或引用会被非法化。
void modify_test(void)
{
std::forward_list<int> 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 9
auto 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
//clear
auto 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 9
std::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的用法,除了不支持逆序迭代外。