• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2025-11-04 14:35 Aet 隐藏边栏 |   抢沙发  1 
文章评分 1 次,平均分 5.0

概述

  1. 首先,stack是一个容器适配器
  2. 理论上,任何提供了 push_back(), pop_back(), back()等操作的序列容器都可以作为 stack的底层容器

为什么默认是deque

  1. deque之所以成为默认选择,是因为它在以下几个方面取得了最佳平衡:
  2. 相对于vector
    1. deque的主要优势在于高效且低成本的动态扩容
    2. vector在尾部空间不足时,需要申请一块更大的内存,然后将所有元素整体搬迁过去,这个操作的时间复杂度是 O(n)
    3. deque采用分段连续的结构,只需要新增一个内存块(buffer)并将其指针添加到中控器(map)中即可,开销要小得多
  3. 相对于list
    1. deque的主要优势在于更高的内存利用率和缓存友好性
    2. list的每个元素都存储在两个指针(前驱和后继),内存开销较大,且节点在内存中不连续,容易造成内存碎片,CPU缓存命中率较低
    3. deque的元素存储在连续的内存块中,虽然块与块之间不连续,但块内是连续的,这在保证高效操作的同时,提供了更好的内存局部性

灵活性:其他容器

  1. 尽管 deque是默认选择,但STL的适配器设计给予了充分的灵活性

stack

设计

类型推导指引

  1. 上述cpp17推导指引1
    1. _Is_allocator<_Container>::value用于判断类型_Container是否为分配器(Allocator
    2. !_Is_allocator<_Container>::value表示:只有当_Container不是分配器类型时,这个推导指引才参与重载决议,有效
      为了避免混淆:用一个分配器对象来构造一个栈,还是想用这个分配器作为底层容器
      此约束明确排除了后一种情况
    3. -> stack<typename _Container::value_type, _Container>
      推导结果:
      告诉编译器:如果使用一个类型为_Container的对象来构造stack,那么最终stack的模板参数应该被推导为stack<typename _Container::value_type, _Container>
      typename _Container::value_type表示从传入的容器类型中提取其元素类型,作为stack的元素类型

  1. 上述cpp17推导指引2
    1. 这个指引用于处理同时传入容器和分配器对象的情况(例如,一个使用自定义分配器的容器)
    2. negation<_Is_allocator<_Container>>:确保第一个参数(_Container)不是分配器类型。这和第一个指引中的约束目的相同
    3. uses_allocator<_Container, _Alloc>:这是一个关键的检查,它判断提供的容器类型_Container是否能够使用提供的分配器类型_Alloc。这确保了容器与分配器是兼容的
    4. 只有同时满足这两个条件,该推导指引才有效
    5. 推导结果与第一个指引相同:stack<typename _Container::value_type, _Container>
      分配器类型_Alloc已经被包含在容器的类型之中(例如,std::vector<int, MyAlloc>本身就包含了分配器信息)

  1. 上述cpp23推导指引1

  1. 上述cpp23推导指引2

  1. 上述cpp23推导指引3

其他

enable_if

  1. enable_if

negation

  1. cpp17对类型特性的布尔值 ::value进行逻辑非运算
  2. std::bool_constant是一个辅助模板,它根据表达式 !bool(B::value)的结果,提供一个 static constexpr bool成员 value
    1. 如果 B::valuetrue,则 negation<B>::valuefalse,反之亦然

conjunction

  1. cpp17对多个类型特征的 ::value进行逻辑与运算
  2. 等价:T1::value && T2::value && ... && Tn::value
  3. 短路特性:一旦某个 Ti::valuefalse,便停止实例化后续类型特征
  4. 空参数包:std::conjunction_v<>结果为 true

is_same

  1. is_same

is_object

  1. cpp11用于在编译时判断一个类型是否属于对象类型
    1. 简单来说,它的核心逻辑是:只要一个类型不是函数、不是引用、也不是 void,那么它就是一个对象类型

is_empty

  1. cpp11引入,用于判断一个类类型是否为空类(empty class
    1. 简单来说,它在编译时告诉你一个类是否不占用任何非静态数据成员存储空间
  2. 一个类类型要被 std::is_empty_v判定为 true,必须同时满足以下严格条件
    1. 非联合体的类类型:必须是 classstruct,但不能是 union
    2. 无非静态数据成员:类中不能有任何非静态成员变量(静态数据成员是允许的)
    3. 无虚函数:类中不能声明或继承虚函数(即没有虚函数表)
    4. 无虚基类:在继承体系中,不能有虚继承(即没有虚基类表)
    5. 无非空基类:所有直接基类本身也必须都是空类

is_final

  1. cpp14引入,用于在编译时判断一个类型是否被声明为 final
    1. 如果类型 T是一个被 final修饰的类类型(包括结构体),则 std::is_final_v<T>的值为 true,否则为 false

空基类优化

标签分发

  1. 使用标签类型来区分不同的构造方式
    1. _Zero_then_variadic_args_t:默认构造 _Ty1,然后使用参数构造 _Ty2
    2. _One_then_variadic_args_t:使用第一个参数构造 _Ty1,剩余参数构造 _Ty2

  1. 标签

声明:本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享