跳转至

常用标准库

I/O 库

主要介绍以下四种:

  • 标准输入输出:std::cinstd::cout
  • 文件输入输出:std::ifstreamstd::ofstreamstd::fstream
  • 格式控制:std::setprecision
  • 字符输入输出:getputgetline

标准输入输出

TODO

文件输入输出

ifstream 只读:

#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::ifstream fin;

    // 在写入前,确保 test.txt 文件存在且有内容
    // 例如,可以手动创建一个 test.txt 并写入 "Hello World"
    fin.open("test.txt", std::ios::in);

    if (!fin.is_open()) {
        std::cerr << "Error opening file for reading!" << std::endl;
        return 1;
    }

    std::string word;
    while (fin >> word) {
        std::cout << word << " ";
    }

    fin.close();

    return 0;
}

ofstream 只写:

#include <iostream>
#include <fstream>

int main() {
    std::ofstream fout;

    fout.open("test.txt", std::ios::out);

    if (!fout.is_open()) {
        std::cerr << "Error opening file for writing!" << std::endl;
        return 1;
    }

    for (int i = 1; i <= 10; i++) {
        fout << i << " ";
    }

    fout.close();

    return 0;
}

fstream 读写:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main() {
    std::fstream fs;

    // 1. 写入内容到文件
    fs.open("test.txt", std::ios::out);
    if (!fs.is_open()) {
        std::cerr << "Error opening file for writing!" << std::endl;
        return 1;
    }
    fs << "Line 1" << std::endl;
    fs << "Line 2" << std::endl;
    fs.close();

    // 2. 从文件读取内容并打印
    fs.open("test.txt", std::ios::in);
    if (!fs.is_open()) {
        std::cerr << "Error opening file for reading!" << std::endl;
        return 1;
    }
    std::string line;
    std::cout << "Reading from file:" << std::endl;
    while (std::getline(fs, line)) {
        std::cout << line << std::endl;
    }
    fs.close();

    return 0;
}

标准模板库

标准模板库 (Standard Template Library, STL) 是 C++ 标准库中,专注于数据结构和算法的部分。主要由以下几个核心组件构成:

  • 容器 (Containers):用来管理和存储数据的类模板
    • 序列容器:std::vectorstd::liststd::deque
    • 关联容器:std::mapstd::setstd::multimapstd::multiset(基于键值,通常有序);
    • 无序关联容器:std::unordered_mapstd::unordered_set(基于哈希,无序但查找快)。
  • 算法 (Algorithms):用来操作容器中数据的函数模板
    • 例如 <algorithm> 中的 std::sort(排序)、std::find(查找)、std::copy(复制)、std::for_each(遍历)。
  • 迭代器 (Iterators):扮演着连接容器和算法的「胶水」角色。它提供了一种统一的方式来访问容器中的元素,使得算法可以不关心容器的具体内部实现,直接通过迭代器进行操作。
  • 函数对象 (Function Objects / Functors):行为像函数的对象,可以作为参数传递给算法,用于自定义算法的行为。例如 std::greater<int>()

STL 最初是由 Alexander Stepanov 和 Meng Lee 在惠普实验室开发的,是一个独立的库。因为它设计得非常出色,后来在1994年被 C++ 标准委员会采纳,并整合进了 C++ 标准库中。

由于这段历史,以及 STL 本身就是一个庞大且自成体系的“库中库”,所以人们习惯上仍然会用 STL 这个名字来特指标准库中源自于它的那部分(容器、算法、迭代器等)。

容器

顺序容器

std::vector<T>:动态数组

std::list<T>:双向链表

std::array<T, N>:定长数组

std::deque<T>:双端队列

关联容器

std::set, std::map:有序红黑树容器,O(logN)

std::unordered_set, std::unordered_map:哈希容器,O(1) 平均查找时间

std::multiset, std::multimap:允许重复键

算法

排序:std::sort, std::stable_sort, std::partial_sort

查找:std::find, std::binary_search, std::find_if

修改:std::reverse, std::rotate, std::replace

统计:std::count, std::accumulate(需 <numeric>

拷贝/移动:std::copy, std::move, std::swap

reverse:想要翻转一个容器,大约有以下三种方法,以 string 为例。

1)方法一:使用 std::reverse() 原地翻转

#include <algorithm>
#include <iostream>

using namespace std;

int main() {
    string s = "hello world!";
    cout << s << "\n";

    reverse(s.begin(), s.end());
    cout << s << "\n";

    return 0;
}

2)方法二:使用 std::reverse_copy 拷贝翻转

#include <algorithm>
#include <iostream>

using namespace std;

int main() {
    string s = "hello world!";
    cout << s << "\n";

    string t(s.size(), ' ');  // 需要提前申请好内存空间
    reverse_copy(s.begin(), s.end(), t.begin());
    cout << t << "\n";

    return 0;
}

3)方法三:重新构造

#include <algorithm>
#include <iostream>

using namespace std;

int main() {
    string s = "hello world!";
    cout << s << "\n";

    string t = string(s.rbegin(), s.rend());
    cout << t << "\n";

    return 0;
}

上述均输出:

hello world!
!dlrow olleh

迭代器

迭代器是一种行为类似指针的对象,它是连接容器和算法的桥梁。通过迭代器,算法可以统一地遍历和操作不同类型的容器,而无需关心容器的内部实现细节。

每种容器都有自己的迭代器类型,例如 std::vector<int>::iterator。常用的操作有:begin() 获取指向第一个元素的迭代器,end() 获取指向末尾(最后一个元素的下一个位置)的迭代器,++ 移动到下一个元素,* 解引用获取元素值。

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {10, 20, 30, 40, 50};

    // 使用迭代器遍历 vector
    for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " "; // 输出: 10 20 30 40 50
    }
    std::cout << std::endl;

    return 0;
}

函数对象

函数对象(Functor)是一个重载了 operator() 的类的对象。它的行为像一个函数,可以被调用,但同时又可以拥有自己的状态。在 STL 中,函数对象常被用作算法的参数,以实现自定义的逻辑,例如自定义排序规则。

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

// 定义一个函数对象,用于比较整数(降序)
struct GreaterThan {
    bool operator()(int a, int b) const {
        return a > b;
    }
};

int main() {
    std::vector<int> v = {5, 2, 8, 1, 9};

    // 使用函数对象作为 sort 的第三个参数
    std::sort(v.begin(), v.end(), GreaterThan()); 

    for (int i : v) {
        std::cout << i << " "; // 输出: 9 8 5 2 1
    }
    std::cout << std::endl;

    return 0;
}

并发库

创建线程:std::thread

等待线程结束:.join(), .detach()

同步机制:std::mutex, std::lock_guard, std::unique_lock

原子变量:std::atomic<T>

任务异步:std::async, std::future, std::promise

下面是一个创建线程和使用互斥锁 std::mutex 保护共享数据的简单示例。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

std::mutex mtx; // 互斥锁
int shared_counter = 0;

// 一个简单的函数,会被多个线程执行
void increment_counter() {
    for (int i = 0; i < 10000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 加锁,函数结束时自动解锁
        shared_counter++;
    }
}

int main() {
    // 创建两个线程
    std::thread t1(increment_counter);
    std::thread t2(increment_counter);

    // 等待两个线程执行完毕
    t1.join();
    t2.join();

    std::cout << "Final counter value: " << shared_counter << std::endl; // 期望输出 20000

    return 0;
}