C++ named requirements: AllocatorAwareContainer (since C++11)
一个 AllocatorAwareContainer 是一种 Container ,它持有一个 Allocator 实例,并在其所有成员函数中使用该实例来分配和释放内存,以及在该内存中构造和销毁对象(这些对象可以是容器元素、节点,或对于无序容器而言的桶数组) ,但 std::basic_string 特化不使用分配器来构造/销毁其元素 (自 C++23 起) 。
以下规则适用于容器构造:
- AllocatorAwareContainer 的拷贝构造函数通过调用被拷贝容器的分配器上的 std:: allocator_traits < allocator_type > :: select_on_container_copy_construction 来获取其分配器实例。
- 移动构造函数通过从原容器的分配器进行移动构造来获取其分配器实例。
- 所有其他构造函数接受一个 const allocator_type & 参数。
替换分配器的唯一方式是复制赋值、移动赋值和交换操作:
- 复制赋值操作仅当 std:: allocator_traits < allocator_type > :: propagate_on_container_copy_assignment :: value 为 true 时才会替换分配器。
- 移动赋值操作仅当 std:: allocator_traits < allocator_type > :: propagate_on_container_move_assignment :: value 为 true 时才会替换分配器。
- 交换操作仅当 std:: allocator_traits < allocator_type > :: propagate_on_container_swap :: value 为 true 时才会替换分配器。具体而言,将通过非限定调用非成员函数 swap 来交换分配器实例,参见 可交换 。若交换操作不传播分配器,则交换两个具有不同分配器的容器将导致未定义行为。
-
访问器
get_allocator()获取用于构造容器或通过最近一次分配器替换操作所安装的分配器的副本。
唯一的例外是 std:: basic_string < CharT,Traits,Allocator > :: assign ,它可能也会传播分配器。
目录 |
要求
若某类型满足 Container 要求,并且在给定以下类型和值的情况下,满足下表中的语义和复杂度要求,则该类型满足 AllocatorAwareContainer 条件:
| 类型 | 定义 |
X
|
一个 AllocatorAwareContainer 类型 |
T
|
X
的
value_type
|
A
|
X
使用的分配器类型
|
| 值 | 定义 |
| a , b |
类型
X
的非 const 左值
|
| c | 类型 const X 的左值 |
| t |
类型
X
的左值或 const 右值
|
| rv |
类型
X
的非 const 右值
|
| m |
类型
A
的值
|
类型
| 名称 | 类型 | 要求 |
|---|---|---|
| typename X :: allocator_type |
A
|
X::allocator_type::value_type
与
X::value_type
必须相同。
|
声明
| 语句 | 语义 | 复杂度 | |
|---|---|---|---|
|
X u
;
X u = X ( ) ; |
前置条件 |
A
满足
DefaultConstructible
要求。
|
常数复杂度 |
| 后置条件 | u. empty ( ) 与 u. get_allocator ( ) == A ( ) 均为 true 。 | ||
| X u ( m ) ; | 后置条件 | u. empty ( ) 与 u. get_allocator ( ) == m 均为 true 。 | 常数复杂度 |
| X u ( t, m ) ; | 前置条件 |
T
满足
CopyInsertable
到
X
的要求。
|
线性复杂度 |
| 后置条件 | u == t 与 u. get_allocator ( ) == m 均为 true 。 | ||
| X u ( rv ) ; | 后置条件 |
|
常数复杂度 |
| X u ( rv, m ) ; | 前置条件 |
T
满足
MoveInsertable
到
X
的要求。
|
|
| 后置条件 |
|
||
表达式
| 表达式 | 类型 | 语义 | 复杂度 | |
|---|---|---|---|---|
| c. get_allocator ( ) |
A
|
无直接语义要求 | 常数 | |
| a = t |
X&
|
前置条件 |
T
需满足
CopyInsertable
至
X
且满足
CopyAssignable
|
线性 |
| 后置条件 | a == t 为 true | |||
| a = rv |
X&
|
前置条件 |
若分配器不会通过移动赋值被替换(参见
上文
),则
T
需满足
MoveInsertable
至
X
且满足
MoveAssignable
|
线性 |
| 效果 | a 的所有现有元素将被移动赋值或销毁 | |||
| 后置条件 | 若 a 与 rv 未引用同一对象,则 a 的值等于赋值前 rv 的值 | |||
| a. swap ( b ) | void | 效果 | 交换 a 与 b 的内容 | 常数 |
注释
AllocatorAwareContainer
总是通过调用
std::
allocator_traits
<
A
>
::
construct
(
m, p, args
)
,在
p
处使用
args
构造类型为
T
的对象,其中
m
==
get_allocator
(
)
。
std::allocator
中默认的
construct
会调用
::
new
(
(
void
*
)
p
)
T
(
args
)
(C++20 前)
std::allocator
没有
construct
成员,构造元素时会调用
std::
construct_at
(
p, args
)
(C++20 起)
,但特化的分配器可以选择不同的定义方式。
标准库
所有标准库字符串类型和容器(除 std::array 与 std:: inplace_vector 外)均为 分配器感知容器 :
|
存储并操作字符序列
(类模板) |
|
|
双端队列
(类模板) |
|
|
(C++11)
|
单向链表
(类模板) |
|
双向链表
(类模板) |
|
|
可调整大小的连续数组
(类模板) |
|
|
键值对集合,按键排序,键唯一
(类模板) |
|
|
键值对集合,按键排序
(类模板) |
|
|
唯一键集合,按键排序
(类模板) |
|
|
键集合,按键排序
(类模板) |
|
|
(C++11)
|
键值对集合,按键哈希,键唯一
(类模板) |
|
(C++11)
|
键值对集合,按键哈希
(类模板) |
|
(C++11)
|
唯一键集合,按键哈希
(类模板) |
|
(C++11)
|
键集合,按键哈希
(类模板) |
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 应用于 | 发布时的行为 | 正确行为 |
|---|---|---|---|
| LWG 2839 | C++11 | 标准容器的自移动赋值操作未被允许 | 允许但结果未作规定 |