C++ 容器

C++ 容器(Containers)详解

在 C++ 标准库(STL, Standard Template Library)中,容器(Container) 是用于存储和管理一组对象的核心组件。它们封装了数据结构与常用操作,使开发者无需手动管理内存或实现底层算法,从而写出更安全、简洁、高效的代码。所有标准容器都是类模板(class templates)!


一、什么是容器?

容器是 C++ 标准库提供的、通用的类模板(class templates),用于组织和操作一组元素。

容器的核心特征:

  • 存储多个同类型元素 (如 int、string、自定义对象等);
  • 自动管理内存 (无需手动 new/delete);
  • 提供统一接口 :如 .size()、.empty()、.begin()、.end();
  • 支持迭代器遍历 和 STL 算法 (如 std::sort, std::find);
  • 类型安全:编译期检查,避免越界(部分容器)。

注意:容器是 标准库预定义的类,不是用户"自定义类"------你使用它们,而不是从零实现它们。


二、容器的分类

C++ 标准将容器分为三大类:

1. 序列容器(Sequence Containers)

元素按线性顺序存储,位置由插入顺序决定。

容器 特点 典型用途
std::vector 动态数组,支持随机访问,尾部插入快 通用首选,替代 C 数组
std::deque 双端队列,首尾插入/删除快 需要双向高效操作
std::list 双向链表,任意位置插入/删除快 频繁中间插入/删除
std::forward_list 单向链表,内存开销最小 内存敏感场景
std::array 固定大小数组(编译期确定) 替代 C 风格数组,更安全
std::string 特化的字符序列容器 存储和操作文本

std::string 虽然用于文本,但技术上属于序列容器!


2. 关联容器(Associative Containers)

基于红黑树 实现,元素按键自动排序,查找效率为 O(log n)。

容器 键是否唯一 是否有序 元素类型
std::set 唯一 ✅ Key
std::multiset 允许重复 ✅ Key
std::map 唯一 ✅ pair<const Key, Value>
std::multimap 允许重复 ✅ pair<const Key, Value>

🔒 map 的键(first)是 const,不可修改!


3. 无序关联容器(Unordered Associative Containers)

基于哈希表 实现,元素无序,平均查找效率为 O(1)。

容器 键是否唯一 是否有序
std::unordered_set 唯一 ❌
std::unordered_multiset 允许重复 ❌
std::unordered_map 唯一 ❌
std::unordered_multimap 允许重复 ❌

⚡ 适合需要快速查找且不关心顺序的场景。


4. 容器适配器(Container Adapters)

基于其他容器封装,限制接口以提供特定行为。

适配器 默认底层容器 行为
std::stack deque 后进先出(LIFO)
std::queue deque 先进先出(FIFO)
std::priority_queue vector 按优先级出队(最大堆)

🛠️ 适配器不支持迭代器,不能遍历!


三、为什么使用容器? vs C 风格数组

对比项 C 风格数组 / 指针 C++ 容器
内存管理 手动(易泄漏、越界) 自动(RAII)
大小动态调整 ❌ 固定大小 ✅ vector、string 等可自动扩容
安全性 低(无边界检查) 高(.at() 有检查,迭代器安全)
功能 仅存储 内置丰富操作(push_back, find, sort 等)
泛型支持 ❌ ✅ 模板 + STL 算法

🚫 示例:C 风格危险代码

c 复制代码
char buf[5];
strcpy(buf, "Hello!"); // 缓冲区溢出!

✅ C++ 安全替代

cpp 复制代码
std::string s = "Hello!"; // 自动分配 7 字节,安全!

四、容器的通用操作示例

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

int main() {
    // 1. 创建容器
    std::vector<int> vec = {3, 1, 4, 1, 5};

    // 2. 遍历(三种方式)
    for (size_t i = 0; i < vec.size(); ++i)        // 索引
        std::cout << vec[i] << " ";
    
    for (auto it = vec.begin(); it != vec.end(); ++it) // 迭代器
        std::cout << *it << " ";
    
    for (const auto& x : vec)                       // 范围 for
        std::cout << x << " ";

    // 3. 使用 STL 算法
    std::sort(vec.begin(), vec.end()); // 排序
    auto pos = std::find(vec.begin(), vec.end(), 4); // 查找

    // 4. string 作为容器
    std::string s = "hello";
    std::reverse(s.begin(), s.end()); // → "olleh"

    return 0;
}

五、常见误区澄清

误区 正确理解
"容器是自己写的类" ❌ 容器是 标准库提供的类模板
"所有类都是容器" ❌ 只有满足容器要求的类才是(如提供 begin()/end())
"string 不是容器" ❌ std::string 是 标准序列容器
"容器一定防止越界" ⚠️ operator[] 不检查,.at() 才抛异常

六、总结

  • 容器是 C++ 现代编程的基石,应优先于 C 风格数组和指针;
  • std::vector 和 std::string 是最常用的容器;
  • 选择容器的原则:
  • 需要随机访问?→ vector
  • 频繁中间插入?→ list
  • 快速按键查找?→ unordered_map
  • 只需栈/队列行为?→ stack / queue
  • 结合 auto、范围 for、STL 算法,写出简洁安全的代码!

记住:在 C++ 中,能用标准容器,就不要手写数组或链表!

相关推荐
朔北之忘 Clancy7 小时前
2025 CSP-J 第二轮真题解析
c++·青少年编程·题解·noip·csp·信奥赛·noi
longlongzihan7 小时前
LeetCode 17电话号码的字母组合:回溯算法(DFS)详解
c++·算法·leetcode·深度优先
落魄实习生7 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
yolo_guo7 小时前
调试mysql延迟与libevent回调实际发送回复时机问题
c++·mysql·libevent
茉莉玫瑰花茶8 小时前
GO [ 方法 ]
开发语言·后端·golang
今晚打老虎8 小时前
c++之提高A(前缀和)(第三课)
数据结构·c++·算法
狗凯之家源码网8 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
by2099910 小时前
从结构体到对象:正式学习C++类的骨架、封装与this指针
c++·经验分享·学习
乌暮10 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习
2601_9622186110 小时前
C语言中三种库的编译和使用方法
开发语言·c++