☰
C++高级进阶--夯实进阶基础--c11(2)
2026/10/24 5:21:14 网站建设 项目流程

C++11

基础语法

1. auto 自动类型推导

不用写复杂类型,编译器自动推。

auto a = 10; // int auto b = 3.14; // double auto vec = vector<int>{1,2,3};
2. 范围 for 循环

遍历容器超简单。

vector<int> v = {1,2,3}; for (auto x : v) { cout << x;
3. nullptr 空指针

比NULL安全,不会和整数混淆。

int* p = nullptr;
4. 列表初始化

统一初始化风格,更安全。

vector<int> v{1,2,3}; int a{10};
5. override / final

防止写错虚函数,强制约束

void func() override; // 必须重写 void func() final; // 不能再重写

智能指针

不用手动 delete,自动释放内存。

1. std::unique_ptr(独占指针)

同一时间只有一个指针拥有对象,最常用、最高效。

#include <memory> unique_ptr<int> p1(new int(10)); auto p2 = make_unique<int>(20); // C++14 // 离开作用域自动释放,无需 delete
2. std::shared_ptr(共享指针)

多个指针共享对象,引用计数为 0 时释放。

shared_ptr<int> p1 = make_shared<int>(10); shared_ptr<int> p2 = p1; // 计数+1 // 最后一个指针销毁时,内存释放
3. std::weak_ptr(解决循环引用)

配合 shared_ptr 使用,不增加引用计数。

weak_ptr<int> wp = sp;

右值引用与移动语义

1.什么是右值?

临时对象(即将销毁、没人用的值)。

int a = 10; // a 是左值 int b = a + 1; // a+1 是右值
2. 右值引用 &&

专门绑定临时对象

int&& rr = 10; // 绑定右值
3. 移动语义

把临时对象的资源 “偷” 过来,不拷贝,速度极快。

string a = "hello"; string b = move(a); // 移动,不是拷贝 // a 变成空,b 直接接管资源
4. 移动构造 / 移动赋值

C++11 自动生成,大幅优化容器性能。

MyClass(MyClass&& other) { // 偷资源 }

一句话总结:拷贝 = 复制数据移动 = 转让所有权

Lambda 表达式

像变量一样写函数,非常方便。

  1. 可以随时定义、就地使用的匿名函数,不用单独写函数名
  2. [捕获列表] (参数) -> 返回值 { 函数体 }; 捕获列表 [=]:值捕获,外部变量只读 [&]:引用捕获,外部变量可修改 [x, &y]:x 值捕获,y 引用捕获 [this]:在类里捕获当前对象 auto add = [](int a, int b) { return a + b; }; cout << add(1,2); // 输出3
  3. lambda表达式的本质是仿函数 类里面重写了()运算符重载 因此可以向函数指针一样使用。

并发编程(多线程标准库)

最核心 4 大件
  1. std::thread 创建线程
  2. std::mutex 互斥锁
  3. std::condition_variable:条件变量(线程等待与唤醒)
  4. std::atomic:原子变量
1.std::thread创建线程
1)基础用法
#include <iostream> #include <thread> using namespace std; void func() { cout << "子线程运行\n"; } int main() { thread t(func); // 启动线程 t.join(); // 等待线程结束(必须写!) return 0; }
2)带参数
void print(int a, string s) { cout << a << " " << s << endl; } int main() { thread t(print, 10, "hello"); t.join(); }
3)Lambda 线程(最常用)
int main() { thread t([]() { cout << "Lambda 线程\n"; }); t.join(); }
4)两个关键函数
  • t.join():等待线程结束(主线程阻塞)
  • t.detach():分离线程(后台运行,主线程不管它)
2.std::mutex互斥锁(解决线程安全)
1)基础锁
int num = 0; std::mutex mtx; void add() { for (int i = 0;num < 10000000; i++) { mtx.lock(); // 加锁 num++; // 同一时间只有一个线程能执行 mtx.unlock(); // 解锁 } } int main() { std::thread t(add); std::thread t1(add); t.join(); t1.join(); std::cout << "num = " << num; }
2)推荐:std::lock_guard(自动锁)

离开作用域自动解锁,不会忘 unlock

int num = 0; std::mutex mtx; void add() { for (int i = 0;num < 10000000; i++) { std::lock_guard<std::mutex>lock(mtx); num++; // 同一时间只有一个线程能执行 } } int main() { std::thread t(add); std::thread t1(add); t.join(); t1.join(); std::cout << "num = " << num; }
3)更灵活:std::unique_lock

支持手动锁 / 解锁、配合条件变量

int num = 0; std::mutex mtx; std::unique_lock<std::mutex> lock(mtx); void add() { for (int i = 0;num < 10000000; i++) { lock.lock(); num++; // 同一时间只有一个线程能执行 lock.unlock(); } } int main() { std::thread t(add); std::thread t1(add); t.join(); t1.join(); std::cout << "num = " << num; }
3.std::condition_variable条件变量(等待 / 唤醒)

必须配合互斥锁使用

用于:生产者 - 消费者模型

  • 线程 A:没数据 →wait()
  • 线程 B:生产数据 →notify_one()唤醒 A
std::mutex mtx; std::condition_variable cv; std::queue<int> q; void producer() { for (int i = 0;i < 5;i++) { std::unique_lock<std::mutex>lock(mtx); q.push(i); std::cout << "生产:" << i << std::endl; cv.notify_one(); // 唤醒消费者 } } void consumer() { while (true) { std::unique_lock<std::mutex>lock(mtx); cv.wait(lock, [] {return !q.empty();}); int val = q.front(); q.pop(); std::cout << "消费:" << val <<std:: endl; if (val == 4) break; } } int main() { std::thread t1(consumer); std::thread t(producer); t1.join();t.join(); std::cout << q.size(); }
4.std::atomic原子变量(无锁安全)

简单类型(int/bool)不用加锁,原子操作 = 线程安全

std::atomic<int>num = 0;//线程安全 void add() { for (int i = 0;num < 10000000; i++) { num++; // 同一时间只有一个线程能执行 } } int main() { std::thread t(add); std::thread t1(add); t.join(); t1.join(); std::cout << "num = " << num; }

异步编程

核心三剑客
  • std::async:启动异步任务(最简单,直接用)
  • std::future:获取异步结果(像 “提货单”)
  • std::promise:手动设置异步结果(底层)
  • std::packaged_task:包装任务,绑定 future(中间层)
1.std::async + std::future

作用

  • 后台开线程跑函数
  • 用future拿返回值
  • 不用自己创建 thread,超级安全

关键点

  • async(任务, 参数...):自动创建线程

  • future<T>:用来接收结果

  • fut.get():只能调用一次,调用时会阻塞等待任务完成

#include <iostream> #include <future> // 异步头文件 #include <thread> #include <chrono> using namespace std; // 耗时任务 int long_task(int a, int b) { this_thread::sleep_for(chrono::seconds(2)); // 模拟耗时 return a + b; } int main() { // 1. 启动异步任务 future<int> fut = async(long_task, 10, 20); cout << "异步任务已启动,主线程继续做别的事..." << endl; // 2. 阻塞等待结果,并获取返回值 int res = fut.get(); cout << "结果:" << res << endl; return 0; }
2.std::async 两种启动策略

立即启动策略

async(launch::async, 任务);

延迟启动策略

async(launch:deferred, 任务);
3.future 常用方法
fut.get(); // 获取结果,阻塞等待 fut.wait(); // 只等待,不拿结果 fut.valid(); // 判断 future 是否有效 fut.wait_for(1s); // 等待最多1秒,超时返回
4.std::promise(手动传值)

作用:手动设置一个值 / 异常,让另一个线程通过 future 获取。

#include <iostream> #include <thread> #include <future> using namespace std; // 子线程函数:接收 promise,手动设置结果 void my_thread(promise<int> prom) { // 计算... prom.set_value(2025); // 手动把结果塞进去 } int main() { // 1. 创建 promise promise<int> prom; // 2. 获取关联的 future(取货单) future<int> fut = prom.get_future(); // 3. 把 promise 交给子线程(必须 move) thread t(my_thread, move(prom)); // 4. 主线程等待结果 cout << "结果:" << fut.get() << endl; t.join(); return 0; }
5.std::packaged_task(包装任务)

作用:把一个函数包装起来,自动把返回值绑定到 future。

#include <iostream> #include <future> #include <thread> using namespace std; // 普通函数 int add(int a, int b) { return a + b; } int main() { // 1. 包装函数:返回值 int,参数 int int packaged_task<int(int, int)> task(add); // 2. 获取 future future<int> fut = task.get_future(); // 3. 交给线程执行 thread t(move(task), 10, 20); // 4. 拿结果 cout << fut.get() << endl; // 30 t.join(); return 0; }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询