C++ STL 教程(实战指南)

C++ STL 教程:从零开始掌握标准模板库

在 C++ 的学习旅程中,你可能会遇到一个既强大又令人敬畏的工具——STL(Standard Template Library,标准模板库)。它不是某个单一的类或函数,而是一套由容器、算法、迭代器、函数对象和适配器组成的完整编程框架。对于初学者来说,STL 仿佛一座迷宫,但一旦掌握,你会发现它能极大提升编码效率,减少重复劳动。

很多人一开始觉得 STL 难懂,是因为它融合了泛型编程的思想,用模板实现通用数据结构。但别担心,我们今天不讲理论堆砌,而是通过一个个真实可用的案例,带你一步步走进 STL 的世界。无论你是刚接触 C++ 的新手,还是已经写过几行代码的中级开发者,这篇 C++ STL 教程 都能帮你建立清晰的体系认知。


容器:数据的“智能仓库”

在编程中,我们经常需要存储和管理一组数据。数组虽然简单,但功能有限。C++ STL 提供了多种容器,它们就像不同类型的仓库,各有特点。

vector:动态数组,灵活又高效

vector 是最常用的容器之一,它是一个动态数组,能自动扩容,使用起来比原生数组更安全。

#include <iostream>
#include <vector>

int main() {
    // 创建一个空的 vector,存储整数类型
    std::vector<int> numbers;

    // 向末尾添加元素
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);

    // 遍历输出所有元素
    for (int i = 0; i < numbers.size(); ++i) {
        std::cout << numbers[i] << " ";  // 输出:10 20 30
    }
    std::cout << std::endl;

    // 使用范围 for 循环(推荐写法)
    for (const int& num : numbers) {
        std::cout << num << " ";  // 输出:10 20 30
    }
    std::cout << std::endl;

    return 0;
}

注释说明:

  • std::vector<int> 声明一个整型向量;
  • push_back() 向尾部添加元素,自动管理内存;
  • size() 返回当前元素个数;
  • 范围 for 循环更简洁,避免手动索引出错。

list:双向链表,插入删除快

当你需要频繁在中间插入或删除元素时,list 是更好的选择。它基于链表实现,插入和删除操作时间复杂度为 O(1),但访问元素需要遍历。

#include <iostream>
#include <list>

int main() {
    std::list<std::string> names;

    // 在开头插入
    names.push_front("Alice");
    names.push_front("Bob");

    // 在末尾插入
    names.push_back("Charlie");

    // 遍历输出
    for (const std::string& name : names) {
        std::cout << name << " ";  // 输出:Bob Alice Charlie
    }
    std::cout << std::endl;

    // 删除第一个元素
    names.pop_front();
    std::cout << "删除后:";
    for (const std::string& name : names) {
        std::cout << name << " ";  // 输出:Alice Charlie
    }
    std::cout << std::endl;

    return 0;
}

注释说明:

  • push_front()push_back() 分别在头尾插入;
  • pop_front() 删除首元素;
  • 适合需要频繁修改数据结构的场景,如任务队列。

算法:让数据“动起来”的魔法

容器只负责存数据,而算法负责处理数据。STL 提供了大量可复用的算法,比如排序、查找、拷贝、变换等。

sort:快速排序,一招搞定乱序数据

假设你有一组无序的成绩,想按从高到低排序,std::sort 就是你的得力助手。

#include <iostream>
#include <vector>
#include <algorithm>  // 包含 sort 算法

int main() {
    std::vector<double> scores = {88.5, 92.0, 76.3, 95.1, 83.7};

    std::cout << "排序前:";
    for (double s : scores) {
        std::cout << s << " ";
    }
    std::cout << std::endl;

    // 对 vector 进行升序排序
    std::sort(scores.begin(), scores.end());

    std::cout << "升序后:";
    for (double s : scores) {
        std::cout << s << " ";
    }
    std::cout << std::endl;

    // 降序排序:传入比较函数
    std::sort(scores.begin(), scores.end(), std::greater<double>());

    std::cout << "降序后:";
    for (double s : scores) {
        std::cout << s << " ";
    }
    std::cout << std::endl;

    return 0;
}

注释说明:

  • begin()end() 返回迭代器,表示容器的起始和结束位置;
  • std::sort 默认升序,std::greater 可实现降序;
  • 时间复杂度平均为 O(n log n),性能优秀。

迭代器:容器的“指针”与“导航仪”

在 STL 中,迭代器是访问容器元素的通用方式。你可以把它想象成一个“导航仪”,让你在容器里“走”来走去,而不必关心底层实现。

常见迭代器类型对比

迭代器类型 用途 是否可修改 支持操作
begin() / end() 指向首元素和尾后位置 可读可写 ++、--、*
rbegin() / rend() 反向遍历 可读可写 ++、--、*
const_iterator 只读访问 不可修改 仅读取
#include <iostream>
#include <vector>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5};

    // 正向遍历
    std::cout << "正向:";
    for (auto it = data.begin(); it != data.end(); ++it) {
        std::cout << *it << " ";  // *it 是当前元素值
    }
    std::cout << std::endl;

    // 反向遍历
    std::cout << "反向:";
    for (auto rit = data.rbegin(); rit != data.rend(); ++rit) {
        std::cout << *rit << " ";  // 从 5 到 1 输出
    }
    std::cout << std::endl;

    return 0;
}

注释说明:

  • auto it = data.begin() 让编译器自动推导类型;
  • it != data.end() 是安全的循环终止条件;
  • ++itit++ 更高效,避免临时对象创建。

函数对象与 lambda:让算法“聪明”起来

STL 的强大之处还在于支持自定义行为。你可以通过函数对象(functor)或 lambda 表达式,为算法“注入”逻辑。

使用 lambda 实现条件筛选

比如我们想从一组数字中找出所有大于 3 的数。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5, 6};

    // 使用 lambda 表达式作为筛选条件
    auto it = std::find_if(nums.begin(), nums.end(), [](int x) {
        return x > 3;  // 如果 x > 3,返回 true
    });

    if (it != nums.end()) {
        std::cout << "第一个大于 3 的数是:" << *it << std::endl;  // 输出:4
    } else {
        std::cout << "没有找到大于 3 的数" << std::endl;
    }

    return 0;
}

注释说明:

  • [](int x) 是 lambda 表达式,接收一个整数参数;
  • return x > 3 是逻辑判断;
  • std::find_if 在范围内查找第一个满足条件的元素。

适配器:为容器“换装”

适配器是一种“包装器”,它能改变已有容器的行为。比如 stackqueue 就是基于 deque 的适配器。

stack:后进先出的“纸堆”

想象你把文件一张张堆起来,只能从顶部拿走最后一张,这就是栈。

#include <iostream>
#include <stack>

int main() {
    std::stack<int> s;

    s.push(10);
    s.push(20);
    s.push(30);

    std::cout << "栈顶元素:" << s.top() << std::endl;  // 输出:30

    while (!s.empty()) {
        std::cout << s.top() << " ";  // 30 20 10
        s.pop();  // 弹出栈顶
    }
    std::cout << std::endl;

    return 0;
}

注释说明:

  • push() 入栈,pop() 出栈,top() 查看栈顶;
  • empty() 判断是否为空,防止越界操作。

总结:从“用”到“懂”的进阶之路

通过这篇 C++ STL 教程,我们系统地学习了容器、算法、迭代器、函数对象和适配器的核心概念。这些组件不是孤立存在的,而是协同工作,构成一个高效、可复用的编程体系。

记住:不要试图一次性掌握所有内容。先从 vectorsort 开始,再逐步尝试 listlambdastack。每一个小练习,都是你构建编程能力的砖石。

当你能在项目中熟练使用 STL 时,你会发现代码更短、更安全、更易读。这正是 C++ 作为系统级语言的优雅之处。

最后提醒一句:STL 的学习不是“背语法”,而是“建立思维模型”。当你能用“容器+算法”的方式思考问题时,你就真正掌握了 C++ 的精髓。

希望这篇文章能成为你 C++ 进阶路上的一盏灯。继续写代码,继续探索,未来可期。