C++ 具名要求:知分配器容器 (AllocatorAwareContainer) (C++11 起)

来自cppreference.com
< cpp‎ | named req


 
 
C++ 具名要求
 

知分配器容器 (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::valuetrue 时,复制赋值才会替换分配器。
  • 只有在 std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::valuetrue 时,移动赋值才会替换分配器 。
  • 只有在 std::allocator_traits<allocator_type>::propagate_on_container_swap::valuetrue 时,交换才会替换分配器。特别是它将通过对非成员函数 swap 的无限定的调用来交换分配器实例,见可交换 (Swappable)

注:如果 propagate_on_container_swapfalse,那么交换两个拥有不相等分配器的容器的行为未定义。

  • 访问器 get_allocator() 获得构造容器时所用的,或为最近的分配器替换操作所安装的分配器的一个副本。

要求

一个类型满足知分配器容器 (AllocatorAwareContainer) 的条件是,它满足容器 (Container) ,并且给定以下类型和值,它也满足下方表格列出的语义和复杂度要求:

类型 定义
X 知分配器容器 (AllocatorAwareContainer) 类型
T Xvalue_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_typeX::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 == tu.get_allocator() == m 都是 true
X u(rv); 后条件
  • u 包含的元素和 rv 在该构造前包含的元素相同。
  • u.get_allocator() 的值和 rv.get_allocator() 在该构造前的值相同。
常数
X u(rv, m); 前条件 T 可移动插入 (MoveInsertable) X 中。
  • m == rv.get_allocator()true时是常数。
  • 否则是线性。
后条件
  • u 包含的元素和 rv 在该构造前包含的元素相同,或者是那些元素的副本。
  • u.get_allocator() == mtrue

表达式

表达式 类型 语义  复杂度 
c.get_allocator() A 没有直接语义要求。 常数
a = t X& 前条件  T 可复制插入 (CopyInsertable) X 中,并且可复制赋值 (CopyAssignable) 线性
后条件 a == ttrue
a = rv X& 前条件 如果分配器不会被移动赋值替换(见上文),那么 T 可移动插入 (MoveInsertable) X 中,并且可移动赋值 (MoveAssignable) 线性
效果 a 先前的所有元素都会被移动赋值或销毁。
后条件 如果 arv 不指代统一对象,那么 a 的值和 rv 在该构造前的值相等。
a.swap(b) void  效果 交换 ab 常数

注解

具分配器容器始终调用 std::allocator_traits<A>::construct(m, p, args)p 中用 args 来构造一个 A 类型的对象,其中 m == get_allocator()std::allocator 中默认的 construct 调用 ::new((void*)p) T(args) (C++20 前)std::allocatorconstruct 成员,而在构造元素时 std::construct_at(p, args) 得到调用 (C++20 起),但特化的分配器可以选择不同的定义。

标准库

所有标准库的字符串类型和容器(除了 std::arraystd::inplace_vector)都是知分配器容器 (AllocatorAwareContainer)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 2839 C++11 不允许标准容器的自移动赋值 容许但结果未指定