九.C++中的容器工具
C++容器类主要包括以下几种:vector、list、deque、set、map、unordered_set、unordered_map等。下面分别给出它们的使用样例:
9.1 vector:动态数组,支持随机访问,插入和删除元素时可能需要移动其他元素。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.push_back(6); // 在末尾添加元素
vec.pop_back(); // 删除末尾元素
std::cout << "vec[2]: " << vec[2] << std::endl; // 访问元素
return 0;
}
9.2 list:双向链表,支持快速插入和删除元素,但不支持随机访问。
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
lst.push_back(6); // 在末尾添加元素
lst.pop_back(); // 删除末尾元素
lst.push_front(0); // 在开头添加元素
lst.pop_front(); // 删除开头元素
return 0;
}
9.3 deque:双端队列,支持在头部和尾部快速插入和删除元素。
#include <iostream>
#include <deque>
int main() {
std::deque<int> deq = {1, 2, 3, 4, 5};
deq.push_back(6); // 在末尾添加元素
deq.pop_back(); // 删除末尾元素
deq.push_front(0); // 在开头添加元素
deq.pop_front(); // 删除开头元素
return 0;
}
9.4 set:基于红黑树实现的有序集合,元素唯一且自动排序。
#include <iostream>
#include <set>
int main() {
std::set<int> st = {1, 2, 3, 4, 5};
st.insert(6); // 插入元素
st.erase(6); // 删除元素
return 0;
}
9.5 map:基于红黑树实现的有序映射,键值对存储,键唯一且自动排序。
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> mp = {{1, "one"}, {2, "two"}, {3, "three"}};
mp[4] = "four"; // 插入键值对
mp.erase(4); // 删除键值对
return 0;
}
9.6 unordered_set:基于哈希表实现的无序集合,元素唯一。
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> ust = {1, 2, 3, 4, 5};
ust.insert(6); // 插入元素
ust.erase(6); // 删除元素
return 0;
}
9.7 unordered_map:基于哈希表实现的无序映射,键值对存储,键唯一。
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_map<int, std::string> ump = {{1, "one"}, {2, "two"}, {3, "three"}};
ump[4] = "four"; // 插入键值对
ump.erase(4); // 删除键值对
return 0;
}
十. C++中的IO流
C中的IO流(Input/Output Streams)是一个强大的工具,用于处理程序的输入和输出。这些流可以是文件、控制台、网络套接字等。C标准库提供了多种IO流类,如std::istream(用于输入),std::ostream(用于输出),std::fstream(用于文件IO),std::cin(用于从控制台读取输入),std::cout(用于向控制台输出)等。
以下是一些使用C++ IO流的样例:
10.1控制台输入输出
#include <iostream>
int main() {
// 输出到控制台
std::cout << "Hello, World!" << std::endl;
// 从控制台读取输入
int number;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "You entered: " << number << std::endl;
return 0;
}
10.2 文件输入输出
#include <iostream>
#include <fstream>
#include <string>
int main() {
// 写入文件
std::ofstream outfile("output.txt"); // 创建一个输出文件流对象
if (outfile.is_open()) {
outfile << "This is a test." << std::endl;
outfile.close(); // 关闭文件
} else {
std::cerr << "Unable to open file";
}
// 读取文件
std::ifstream infile("output.txt"); // 创建一个输入文件流对象
std::string content;
if (infile.is_open()) {
std::getline(infile, content); // 读取一行内容
infile.close(); // 关闭文件
std::cout << "File content: " << content << std::endl;
} else {
std::cerr << "Unable to open file";
}
return 0;
}
10.3 使用std::stringstream进行字符串处理
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string str = "123 456";
std::stringstream ss(str); // 创建一个stringstream对象,并初始化为str
int num1, num2;
char space;
// 从stringstream中读取数据
ss >> num1 >> space >> num2;
std::cout << "num1: " << num1 << ", num2: " << num2 << std::endl;
return 0;
}
10.4 格式化输出
#include <iostream>
#include <iomanip> // 用于控制格式
int main() {
double pi = 3.14159265358979323846;
// 设置输出精度和宽度
std::cout << std::fixed << std::setprecision(2) << "Value of pi: " << pi << std::endl;
// 设置填充字符和字段宽度
std::cout << std::setw(10) << std::setfill('*') << "Right Aligned" << std::endl;
std::cout << std::setw(10) << std::left << std::setfill('*') << "Left Aligned" << std::endl;
return 0;
}
以上代码示例演示了如何在C中使用不同类型的IO流,包括控制台输入输出、文件IO、字符串处理以及格式化输出。这些流操作使C能够方便地处理各种输入和输出任务。
十一.C++中的多线程
C11及之后的版本引入了线程库,使得在C中创建和管理多线程变得更加容易和直观。C++的线程库包含在一个名为<thread>的头文件中,并提供了一个std::thread类来表示和管理线程。
以下是C++中多线程的一些基本用法:
11.1 创建线程
使用std::thread类创建一个新线程,并传递给它一个可调用的目标(如函数、函数对象、Lambda表达式或成员函数及对象)。
#include <iostream>
#include <thread>
void print_hello() {
std::cout << "Hello from thread " << std::this_thread::get_id() << '\n';
}
int main() {
std::thread t(print_hello); // 创建一个新线程来运行print_hello函数
t.join(); // 等待线程完成
return 0;
}
11.2 传递参数给线程函数
你可以通过构造函数将参数传递给线程函数。
#include <iostream>
#include <thread>
void print_number(int num) {
std::cout << "Number is " << num << " from thread " << std::this_thread::get_id() << '\n';
}
int main() {
std::thread t(print_number, 42); // 创建一个新线程来运行print_number函数,并传递参数42
t.join(); // 等待线程完成
return 0;
}
11.3 分离线程
使用std::thread::detach()方法可以使线程在后台运行,而不需要等待其完成。
#include <iostream>
#include <thread>
void print_hello() {
std::cout << "Hello from detached thread " << std::this_thread::get_id() << '\n';
}
int main() {
std::thread t(print_hello);
t.detach(); // 线程在后台运行,main函数不会等待它完成
return 0; // 主线程结束,但后台线程可能还在运行
}
11.4 线程ID和当前线程
std::this_thread::get_id()函数返回当前线程的ID。
11.5 线程同步
C++提供了多种机制来实现线程同步,包括互斥量(std::mutex)、条件变量(std::condition_variable)、锁保护(std::lock_guard和std::unique_lock)、原子操作(std::atomic)等。
11.6 线程安全
在多线程编程中,必须确保代码是线程安全的,即多个线程同时访问共享数据时,不会导致数据损坏或不一致的结果。这通常通过使用互斥量、原子操作或同步原语来实现。
11.7 线程局部存储
thread_local关键字可以在C++中声明线程局部存储的变量。这些变量在每个线程中都有自己的副本,因此可以在不同线程中安全地访问和修改它们,而不会互相干扰。
示例:使用互斥量保护共享数据
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 全局互斥量
int counter = 0; // 共享数据
void increment() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 使用锁保护区域
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value is " << counter << '\n';
return 0;
}
在上面的示例中,我们使用了一个互斥量mtx来保护对共享变量counter的访问,确保两个线程不会同时修改它。