C++ 命名要求: AllocatorAwareContainer (自 C++11 起)
AllocatorAwareContainer 是一种Container,它持有一个Allocator实例,并在其所有成员函数中使用该实例来分配和释放内存,以及在该内存中构造和销毁对象(这些对象可以是容器元素、节点,或者对于无序容器,是桶数组),但std::basic_string特化不使用分配器来构造/销毁其元素 (自 C++23 起)。
以下规则适用于容器构造
- AllocatorAwareContainers 的拷贝构造函数通过在被拷贝容器的分配器上调用
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 来交换分配器实例,参见Swappable。
注意:如果 propagate_on_container_swap 为false,则交换两个分配器不相等的容器是未定义行为。
- 访问器 get_allocator() 获取用于构造容器或最近的分配器替换操作安装的分配器的副本。
要求
图例
X
- 容器类型
T
- 元素类型
A
- T 的分配器
a
, b
- X 类型的对象(非 const 左值)
t
- X 类型的对象(左值或 const 右值)
rv
- X 类型的对象(非 const 右值)
m
- A 类型的对象
表达式 | 返回类型 | 前/要求 | 后/效果 | 复杂度 |
---|---|---|---|---|
allocator_type | A | allocator_type::value_type 必须与 X::value_type 相同 | 编译时 | |
get_allocator() | A | 常量 | ||
X u; | A 是DefaultConstructible | u.empty() == true && u.get_allocator() == A() | 常量 | |
X u(m); | u.empty() == true && u.get_allocator() == m | 常量 | ||
X u(t,m); | T 是CopyInsertable到X中 | u == t && u.get_allocator() == m | 线性 | |
X u(rv); | A 的移动构造函数不得抛出异常 | u 具有与构造前 rv 相同的元素和相等的分配器 | 常量 | |
X u(rv,m); | T 是MoveInsertable到X中 | u 的元素与 rv 的元素相同或为副本,并且 u.get_allocator() == m | 如果 m == rv.get_allocator() 则为常数,否则为线性 | |
a = t | X& | T 是CopyInsertable到X中且CopyAssignable | a == t | 线性 |
a = rv | X& | 如果分配器不会被移动赋值替换(见上文),则T是MoveInsertable到X中且MoveAssignable | a 的所有现有元素要么被移动赋值,要么被销毁;如果 a 和 rv 不指向同一个对象,则 a 等于赋值前 rv 的值。 | 线性 |
a.swap(b) | void | 交换 a 和 b 的内容 | 常量 |
备注
Allocator-aware 容器总是调用 std::allocator_traits<A>::construct(m, p, args)
来在 p
处使用 args
构造一个 T
类型的对象,其中 m == get_allocator()
。std::allocator
中的默认构造调用 ::new((void*)p) T(args)
(直到 C++20) std::allocator
没有 construct 成员,并且在构造元素时调用 std::construct_at(p, args)
(自 C++20 起),但专门的分配器可以选择不同的定义
标准库
- std::basic_string
- std::deque
- std::forward_list
- std::list
- std::vector
- std::map
- std::multimap
- std::set
- std::multiset
- std::unordered_map
- std::unordered_multimap
- std::unordered_set
- std::unordered_multiset
缺陷报告
以下改变行为的缺陷报告已追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 发布时的行为 | 正确行为 |
---|---|---|---|
LWG 2839 | C++11 | 标准容器的自移动赋值不被允许 | 允许,但结果未指定 |