命名空间
变体
操作

C++ 命名需求: SequenceContainer

来自 cppreference.com
 
 
C++ 命名需求
 

一个 SequenceContainer 是一个 Container,它以线性排列方式存储相同类型的对象。

内容

[编辑] 需求

图例
X 一个顺序容器类
T X 的元素类型
a X 类型的值
u 已声明变量的名称
A X 的分配器类型
i, j LegacyInputIterators,使得 [ij) 是一个有效的范围,并且迭代器引用隐式可转换为 value_type 的元素。
rg (自 C++23 起) 类型 R 的值,该类型模拟 container-compatible-range<T>
il (自 C++11 起) 类型 std::initializer_list<value_type> 的对象。
n 类型 X::size_type 的值。
p 一个指向 a 的有效 const 迭代器
q 一个指向 a 的有效可解引用的 const 迭代器
q1, q2 指向 a 的两个 const 迭代器,使得 [q1q2) 是一个有效的范围。
t 类型 X::value_type左值 或 const 右值(自 C++11 起)
rv (自 C++11 起) 类型 X::value_type 的非 const 右值。
Args (自 C++11 起) 一个模板参数包。
args (自 C++11 起) 一个具有模式 Arg&& 的函数参数包。

类型 X 满足 SequenceContainer,如果

  • 类型 X 满足 Container,并且
  • 以下语句和表达式对于所有顺序容器std::array (见 说明)(自 C++11 起) 必须有效,并具有指定的效用。
语句 效用     条件[1]
X u(n, t) 构造包含 nt 副本的顺序容器。 前提 TCopyInsertableX 中的。
后置 std::distance(u.begin(), u.end())
    == n
X u(i, j) 构造与范围 [ij) 元素相等的顺序容器。 前提 TEmplaceConstructible*iX 中的。
后置 std::distance(u.begin(), u.end())
    == std::distance(i, j)
表达式 类型 效用 条件
X(std::from_range, rg)
(自 C++23 起)
X 构造与范围 rg 元素相等的顺序容器。 前提 TEmplaceConstructible*ranges::begin(rg)X 中的。
后置
X(il)
(自 C++11 起)
X 等效于 X(il.begin(),
    il.end())
没有显式需求。
a = il
(自 C++11 起)
X& il 表示的范围赋值到 a 中。[2] 前提 TCopyInsertableCopyAssignable
后置 a 中的现有元素被销毁或赋值。
a.emplace(p, args)
(自 C++11 起)
iterator p 之前插入一个类型为 T 的对象,使用 std::forward<Args>(args) 构造。 前提 TEmplaceConstructible
后置 返回的迭代器指向从 args 构造到 a 中的元素。
a.insert(p, t) iterator p 之前插入 t 的副本。 前提 TCopyInsertable
后置 返回的迭代器指向插入到 a 中的 t 的副本。
a.insert(p, rv)
(自 C++11 起)
iterator p 之前插入 rv 的副本,可能使用移动语义。 前提 TMoveInsertable
后置 返回的迭代器指向插入到 a 中的 rv 的副本。
a.insert(p, n, t) iterator p 之前插入 nt 的副本。 前提 TCopyInsertableCopyAssignable
后置 返回的迭代器指向插入到 a 中的第一个元素的副本,或者当 n == 0 时为 p
a.insert(p, i, j) iterator 插入元素的副本
[ij)p 之前。
前提 TEmplaceConstructible,并且 ij 不在 a 中。
后置
  • [ij) 中的每个迭代器都被解引用一次。
  • 返回的迭代器指向插入到 a 中的第一个元素的副本,或者当 i == j 时为 p
a.insert_range(p, rg)
(自 C++23 起)
iterator p 之前插入 rg 中元素的副本。 前提
后置
  • 范围 rg 中的每个迭代器都被解引用一次。
  • 返回的迭代器指向插入到 a 中的第一个元素的副本,或者如果 rg 为空,则指向 p
a.insert(p, il)
(自 C++11 起)
iterator 等效于 a.insert(p,
         il.begin(),
         il.end())
前提 没有显式需求。
后置 返回的迭代器指向插入到 a 中的第一个元素的副本,或者如果 il 为空,则指向 p
a.erase(q) iterator 删除 q 指向的元素。 前提 没有显式需求。
后置 返回的迭代器指向在删除之前紧随 q 的元素,或者如果不存在这样的元素,则指向 a.end()
a.erase(q1, q2) iterator 删除 [q1q2) 中的元素。 前提 没有显式需求。
后置 返回的迭代器指向在任何删除之前由 q2 指向的元素,或者如果不存在这样的元素,则指向 a.end()
a.clear() void 销毁 a 中的所有元素。 前提 没有显式需求。
后置
  • 所有引用、指针和迭代器都失效,包括结束迭代器。
  • a.empty()true
a.assign(i, j) void [ij) 的副本替换 a 中的元素。 前提
后置 [ij) 中的每个迭代器都被解引用一次。
a.assign_range(rg)
(自 C++23 起)
void rg 中每个元素的副本替换 a 中的元素。 前提
后置
  • 范围 rg 中的每个迭代器都被解引用一次。
  • 所有引用、指针和迭代器都失效。
a.assign(il)
(自 C++11 起)
void 等效于

a.assign(il.begin(),
         il.end())

没有显式需求。
a.assign(n, t) void nt 的副本替换 a 中的元素。 前提 TCopyInsertableCopyAssignable
后置 没有显式需求。
注释
  1. 对于效果等效于其他操作的表达式,那些操作内部的表达式的条件继承在表中列出的条件之上。
  2. std::array 支持从大括号初始化列表进行赋值,但不支持从 std::initializer_list 进行赋值。
  3. TR 是类型,使得 std::assignable_from<T&, ranges::range_reference_t<R>> 建模。

[edit] 可选操作

以下表达式对于命名的序列容器必须有效并具有其指定的效果,所有操作 除了 prepend_rangeappend_range(自 C++23 起) 占用摊销常数时间。

表达式 类型 效用     先决条件[1] 容器
a.front() reference,或者

对于 const aconst_reference

返回 *a.begin() 没有显式需求。 std::basic_stringstd::arraystd::dequestd::forward_liststd::inplace_vectorstd::liststd::vector
a.back() reference,或者

对于 const aconst_reference

等效于 auto tmp = a.end();
--tmp;
return *tmp;
没有显式需求。 std::basic_stringstd::arraystd::dequestd::inplace_vectorstd::liststd::vector
a.emplace_front(args)
(自 C++11 起)
void 在开头添加一个使用 std::forward<Args>
    (args)...
构造的 T
TEmplaceConstructible,可以从 args 构建到 X 中。 std::dequestd::forward_liststd::list
a.emplace_back(args)
(自 C++11 起)
void 使用 std::forward<Args>
    (args)...
构造的 T 追加到末尾。
TEmplaceConstructible,可以从 args 构建到 X 中。 std::deque, std::inplace_vector, std::list, std::vector
a.push_front(t) void 在容器头部追加 t 的副本。 TCopyInsertableX 中的。 std::dequestd::forward_liststd::list
a.push_front(rv)
(自 C++11 起)
void 在容器头部追加 rv 的副本,可能使用移动语义。 TMoveInsertableX 中。
a.prepend_range(rg)
(自 C++23 起)
void begin() 之前插入 [2] rg 中元素的副本,rg 中的每个迭代器都被解引用一次。 TEmplaceConstructible*ranges::begin(rg)X 中的。 std::dequestd::forward_liststd::list
a.push_back(t) void 在容器尾部追加 t 的副本。 TCopyInsertableX 中的。 std::basic_string, std::deque, std::inplace_vector, std::list, std::vector
a.push_back(rv)
(自 C++11 起)
void 在容器尾部追加 rv 的副本,可能使用移动语义。 TMoveInsertableX 中。
a.append_range(rg)
(自 C++23 起)
void end() 之前插入 [2] rg 中元素的副本,每个迭代器都被解引用一次。 TEmplaceConstructible*ranges::begin(rg)X 中的。 std::deque, std::inplace_vector, std::list, std::vector
a.pop_front() void 销毁第一个元素。 a.empty()false std::dequestd::forward_liststd::list
a.pop_back() void 销毁最后一个元素。 a.empty()false std::basic_string, std::deque, std::inplace_vector, std::list, std::vector
a[n] reference,或者

对于 const aconst_reference

返回 *(a.begin() + n) 没有显式需求。 std::basic_string, std::array, std::deque, std::inplace_vector, std::vector
a.at(n) reference,或者

对于 const aconst_reference

返回 *(a.begin() + n),如果 n >= size() 则抛出 std::out_of_range 没有显式需求。
备注
  1. 对于其效果等同于其他操作的表达式,这些操作内部表达式的先决条件会继承到表中列出的先决条件之上。
  2. 2.0 2.1 插入顺序相对于 rg 中元素的顺序不反转。

此外,对于每个序列容器

  • 如果相应的模板参数不满足 LegacyInputIterator,则接受两个输入迭代器的构造函数模板以及 insertappendassignreplace 的成员函数模板重载,这些重载接受两个输入迭代器,将不会参与重载解析。
  • 如果分别为该参数推断出不符合输入迭代器或分配器的类型,则具有 LegacyInputIteratorAllocator 模板参数的推断指南将不会参与重载解析。
(自 C++17 起)

[edit] 标准库中的序列容器

存储和操作字符序列
(类模板) [edit]
(C++11)
固定大小的原地连续数组
(类模板) [edit]
动态连续数组
(类模板) [edit]
动态可调整大小、固定容量、原地连续数组
(类模板) [edit]
双端队列
(类模板) [edit]
单链表
(类模板) [edit]
双链表
(类模板) [edit]

[edit] 权衡/使用说明

std::vector 快速访问,但插入/删除效率大多很低。
std::inplace_vector 快速访问,原地连续存储,但容量固定且插入/删除效率大多很低。
std::array 快速访问,原地连续存储,但元素数量固定且无法插入/删除。
std::deque 快速访问,在序列开头/结尾处高效插入/删除,但在中间位置效率不高。
std::list
std::forward_list
在序列中间高效插入/删除,但访问大多是线性时间。

[edit] 缺陷报告

以下行为变更缺陷报告被追溯应用于之前发布的 C++ 标准。

DR 应用于 发布的行为 正确行为
LWG 139 C++98 可选操作不需要
在指定的容器中实现
需要,并以
摊销时间
LWG 149 C++98 a.insert(p, t) 返回 iterator
a.insert(p, n, t)a.insert(p, n, t) 返回 void
它们都返回
iterator
LWG 151 C++98 q1 需要可解引用 [1] 它可以不可解引用
LWG 355 C++98 调用 a.back()a.pop_back()
执行 --a.end(),这是危险的 [2]
递减一个副本
而不是 a.end()
LWG 589 C++98 ij 所引用的元素
可能无法转换为 value_type
它们是隐式地
可转换为 value_type
LWG 3927 C++98 operator[] 没有隐式要求 添加了隐式要求
  1. 这是一个缺陷,因为它会导致 a.erase(a.begin(), a.end()) 的行为未定义,如果 a 是一个空容器。
  2. 如果 a.end() 的类型是基本类型,则 --a.end() 形成错误。当 a 的类型是模板化的时,这个错误是危险的,在这种情况下,这个错误很难被发现。