📖目录
- [前言:VC++6.0 的幽灵还在游荡](#前言:VC++6.0 的幽灵还在游荡)
- [1. 内存安全革命 ------ 智能指针如何终结 `new/delete` 地狱](#1. 内存安全革命 —— 智能指针如何终结
new/delete地狱) -
- [1.1 裸指针的三大原罪](#1.1 裸指针的三大原罪)
- [1.2 `unique_ptr`:独占所有权(像租用共享单车)](#1.2
unique_ptr:独占所有权(像租用共享单车)) - [1.3 `shared_ptr` + `weak_ptr`:共享与防循环引用(像多人合租快递柜)](#1.3
shared_ptr+weak_ptr:共享与防循环引用(像多人合租快递柜))
- [2. 并发安全革命 ------ 从裸线程到 C++20 协程](#2. 并发安全革命 —— 从裸线程到 C++20 协程)
-
- [2.1 裸线程 vs `std::jthread`(自动 join 的快递员)](#2.1 裸线程 vs
std::jthread(自动 join 的快递员)) - [2.2 原子操作:`std::atomic` 与内存序](#2.2 原子操作:
std::atomic与内存序) - [2.3 同步原语:`mutex` + `scoped_lock`](#2.3 同步原语:
mutex+scoped_lock) - [2.4 异步任务:`std::async` + `future`](#2.4 异步任务:
std::async+future)
- [2.1 裸线程 vs `std::jthread`(自动 join 的快递员)](#2.1 裸线程 vs
- [3. C++20 协程实战 ------ 异步即同步](#3. C++20 协程实战 —— 异步即同步)
-
- [3.1 协程核心概念大白话](#3.1 协程核心概念大白话)
- [3.2 让 co_await 跑起来:task<void> 初探(最简可运行)](#3.2 让 co_await 跑起来:task<void> 初探(最简可运行))
- [3.3 真实挂起与恢复:基于事件循环的协程调度器(完整可运行)](#3.3 真实挂起与恢复:基于事件循环的协程调度器(完整可运行))
- [4. 性能对比与工程建议](#4. 性能对比与工程建议)
- [5. 总结 & 下一篇预告](#5. 总结 & 下一篇预告)
- [6. 参考资料 & 往期文章](#6. 参考资料 & 往期文章)
前言:VC++6.0 的幽灵还在游荡
在 2025 年,仍有大量 C++ 项目运行在 VC++6.0 上------没有模板偏特化、没有 STL 安全性、没有 RAII、没有多线程标准库。开发者每天与 new[] / delete[]、_beginthreadex、CRITICAL_SECTION 打交道,如同在雷区跳舞。
而现代 C++(C++11 ~ C++20)完成了两大革命:
- 内存安全:通过智能指针消灭野指针、内存泄漏;
- 并发安全:通过 RAII 线程、原子操作、协程消灭数据竞争、死锁、回调地狱。
本文将带你从零构建现代 C++ 编程范式 ,所有代码均可在 VS2022 / GCC10+ / Clang14+ 上编译运行(需启用 C++20)。
1. 内存安全革命 ------ 智能指针如何终结 new/delete 地狱
1.1 裸指针的三大原罪
cpp
// VC++6.0 风格:危险三连
int* p = new int(42);
// 忘记 delete? → 内存泄漏
// 多次 delete? → 崩溃
// 异常抛出? → 永远不会 delete
💥 现实案例:某金融系统因未释放交易缓存,72 小时后 OOM 崩溃。
1.2 unique_ptr:独占所有权(像租用共享单车)
cpp
// 文件:unique_ptr_demo.cpp
#include <memory>
#include <iostream>
class Package {
public:
Package(int id) : id_(id) { std::cout << "📦 Package " << id_ << " created\n"; }
~Package() { std::cout << "🗑️ Package " << id_ << " destroyed\n"; }
void deliver() { std::cout << "🚚 Delivering package " << id_ << "\n"; }
private:
int id_;
};
int main() {
// unique_ptr:唯一拥有者,离开作用域自动 delete
std::unique_ptr<Package> pkg = std::make_unique<Package>(1001);
pkg->deliver();
// 无法复制,只能转移
auto pkg2 = std::move(pkg); // pkg 变为空
if (pkg == nullptr) {
std::cout << "Original pointer is now null\n";
}
return 0;
// pkg2 析构 → Package 自动销毁
}
✅ 输出 :

1.3 shared_ptr + weak_ptr:共享与防循环引用(像多人合租快递柜)
cpp
// 文件:shared_weak_demo.cpp
#include <memory>
#include <iostream>
struct Node;
using NodePtr = std::shared_ptr<Node>;
using WeakNodePtr = std::weak_ptr<Node>;
struct Node {
int value;
NodePtr next;
WeakNodePtr prev; // 用 weak_ptr 避免循环引用!
Node(int v) : value(v) { std::cout << "Node " << v << " created\n"; }
~Node() { std::cout << "Node " << value << " destroyed\n"; }
};
int main() {
auto n1 = std::make_shared<Node>(1);
auto n2 = std::make_shared<Node>(2);
n1->next = n2;
n2->prev = n1; // weak_ptr,不增加引用计数
std::cout << "n1 use_count: " << n1.use_count() << "\n"; // 1
std::cout << "n2 use_count: " << n2.use_count() << "\n"; // 1
return 0;
// 无循环引用 → 两个节点正常析构
}
✅ 输出 :

❌ 若
prev也是shared_ptr,则use_count永远 ≥1,内存泄漏!
2. 并发安全革命 ------ 从裸线程到 C++20 协程
2.1 裸线程 vs std::jthread(自动 join 的快递员)
cpp
// 文件:jthread_vs_raw.cpp
#include <iostream>
#include <thread>
#include <chrono>
void worker(int id) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Worker " << id << " done\n";
}
int main() {
// C++20 jthread:自动 join
std::jthread t1(worker, 1);
// 对比:std::thread 必须手动 join
std::thread t2(worker, 2);
t2.join(); // 忘记这句?程序 terminate!
return 0;
}
✅ 输出 :

2.2 原子操作:std::atomic 与内存序
cpp
// 文件:atomic_counter_full.cpp
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
std::atomic<int> counter{0};
void increment() {
for (int i = 0; i < 10000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed);
}
}
int main() {
std::vector<std::jthread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(increment);
}
// 结果一定是 40000
std::cout << "Final counter: " << counter.load() << "\n";
return 0;
}
✅ 输出 :

2.3 同步原语:mutex + scoped_lock
cpp
// 文件:mutex_logging.cpp
#include <mutex>
#include <iostream>
#include <thread>
#include <vector>
std::mutex cout_mutex;
void log_safe(int id) {
std::scoped_lock lock(cout_mutex);
std::cout << "Thread " << id << " writing log...\n";
}
int main() {
std::vector<std::jthread> workers;
for (int i = 0; i < 5; ++i) {
workers.emplace_back(log_safe, i);
}
return 0;
}
✅ 输出 :

2.4 异步任务:std::async + future
cpp
// 文件:async_future.cpp
#include <future>
#include <iostream>
#include <chrono>
int compute() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 123;
}
int main() {
auto fut = std::async(std::launch::async, compute);
std::cout << "Waiting for result...\n";
int result = fut.get();
std::cout << "Result: " << result << "\n";
return 0;
}
✅ 输出 :

3. C++20 协程实战 ------ 异步即同步
3.1 协程核心概念大白话
co_await:请求挂起当前协程,直到被 await 的操作完成后再继续。是否真正挂起,取决于 awaitable 对象的实现。- 协程本身不会创建新线程------它们在调用线程上运行,通过协作式调度实现并发。
注意:下面的示例使用一个立即恢复的 awaiter,因此协程不会实际暂停。这仅用于演示基本语法。后续我们会展示真正的挂起与恢复。
3.2 让 co_await 跑起来:task 初探(最简可运行)
cpp
// main.cpp
#include <iostream>
#include <coroutine>
#include <exception>
#include <stdexcept> // <-- REQUIRED for std::runtime_error
struct task {
struct promise_type {
task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
};
struct delay_awaiter {
bool await_ready() const noexcept {
return false;
}
void await_suspend(std::coroutine_handle<> handle) const noexcept {
handle.resume();
}
void await_resume() const noexcept {}
};
delay_awaiter simulate_async_work() {
std::cout << "Simulating async work...\n";
return {};
}
task my_coroutine() {
std::cout << "1. Start coroutine\n";
co_await simulate_async_work();
std::cout << "3. Coroutine resumed\n";
}
int main() {
std::cout << "0. Before calling coroutine\n";
my_coroutine();
std::cout << "2. After calling coroutine\n";
return 0;
}
✅ 输出 :

💡 关键点 :协程中可安全使用
unique_ptr/shared_ptr,RAII 依然生效!
3.3 真实挂起与恢复:基于事件循环的协程调度器(完整可运行)
💡 目标:展示协程如何在不创建新线程的情况下,通过
co_await挂起,并在"未来某个时刻"被事件循环恢复执行。
cpp
// 文件:coroutine_scheduler.cpp
// 编译命令(VS2022、VS2026):
// cl /std:c++20 /EHsc coroutine_scheduler.cpp
// GCC/Clang: g++ -std=c++20 -O2 coroutine_scheduler.cpp -pthread
#include <iostream>
#include <coroutine>
#include <vector>
#include <queue>
#include <chrono>
#include <thread>
#include <functional>
#include <optional>
// ----------------------------
// 1. 简单的时间点类型(毫秒)
// ----------------------------
using TimePoint = std::chrono::steady_clock::time_point;
using Duration = std::chrono::milliseconds;
// ----------------------------
// 2. 事件循环(单线程调度器)
// ----------------------------
class EventLoop {
public:
// 注册一个在未来 time 点执行的回调
void schedule(TimePoint time, std::function<void()> callback) {
tasks_.push({time, std::move(callback)});
}
// 运行事件循环,直到所有任务完成
void run() {
while (!tasks_.empty()) {
auto now = std::chrono::steady_clock::now();
auto& [time, cb] = tasks_.top();
if (now >= time) {
cb(); // 执行协程恢复
tasks_.pop();
} else {
std::this_thread::sleep_until(time);
}
}
}
private:
struct Task {
TimePoint time;
std::function<void()> callback;
bool operator>(const Task& other) const {
return time > other.time;
}
};
std::priority_queue<Task, std::vector<Task>, std::greater<Task>> tasks_;
};
// 全局事件循环(简化设计)
EventLoop g_loop;
// ----------------------------
// 3. 可 await 的 delay 对象
// ----------------------------
struct DelayAwaiter {
Duration delay_;
explicit DelayAwaiter(Duration d) : delay_(d) {}
bool await_ready() const noexcept {
return false; // 总是挂起
}
void await_suspend(std::coroutine_handle<> handle) const {
auto resume_time = std::chrono::steady_clock::now() + delay_;
g_loop.schedule(resume_time, [handle]() {
handle.resume(); // 在事件循环中恢复协程
});
}
void await_resume() const noexcept {}
};
DelayAwaiter delay(Duration ms) {
return DelayAwaiter{ms};
}
// ----------------------------
// 4. 支持返回值的 task<T>(简化版)
// ----------------------------
template<typename T>
struct task {
struct promise_type {
T value_;
std::exception_ptr ex_;
task get_return_object() { return task{std::coroutine_handle<promise_type>::from_promise(*this)}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
template<typename U>
void return_value(U&& val) { value_ = std::forward<U>(val); }
void unhandled_exception() { ex_ = std::current_exception(); }
~promise_type() = default;
};
using handle_type = std::coroutine_handle<promise_type>;
handle_type coro_;
explicit task(handle_type h) : coro_(h) {}
task(const task&) = delete;
task& operator=(const task&) = delete;
task(task&& other) noexcept : coro_(other.coro_) { other.coro_ = nullptr; }
~task() {
if (coro_) coro_.destroy();
}
T get() {
coro_.resume(); // 触发 final_suspend 前的最后一次 resume
if (coro_.promise().ex_)
std::rethrow_exception(coro_.promise().ex_);
return std::move(coro_.promise().value_);
}
};
// ----------------------------
// 5. 协程函数示例
// ----------------------------
task<int> async_computation() {
std::cout << "[Coroutine] Start async computation...\n";
co_await delay(1000ms); // 挂起 1 秒
std::cout << "[Coroutine] Resumed after delay!\n";
co_return 42;
}
// ----------------------------
// 6. 主函数
// ----------------------------
int main() {
std::cout << "0. Main starts\n";
// 启动协程(不会立即执行完)
task<int> t = async_computation();
std::cout << "1. Coroutine launched, now running event loop...\n";
// 运行事件循环,驱动协程恢复
g_loop.run();
std::cout << "2. Event loop done, getting result...\n";
int result = t.get();
std::cout << "3. Result = " << result << "\n";
return 0;
}
✅ 预期输出(顺序严格):

🔍 关键说明:
- 协程没有创建新线程:整个程序只在主线程运行。
delay(1000ms)真正挂起协程 :通过await_suspend将恢复逻辑注册到事件循环。- 事件循环驱动恢复 :
g_loop.run()在 1 秒后调用handle.resume(),协程继续执行。 - 支持返回值 :
task<int>可co_return并通过.get()获取结果。 - 异常安全 :若协程内抛异常,会被捕获并通过
.get()重新抛出。
🛠️ 编译提示(Visual Studio 2022):
- 项目属性 → C/C++ → 语言 → C++ 语言标准:ISO C++20 标准 (/std:c++20)
- 不需要额外链接库(纯标准库实现)
4. 性能对比与工程建议
| 技术 | 内存开销 | 线程数 | 适用场景 |
|---|---|---|---|
| 裸指针 + 裸线程 | 高 + 高 | N/A | 遗留系统维护 |
unique_ptr + jthread |
低 + 中 | CPU 密集型 | |
shared_ptr + C++20 协程 |
极低 + 1 | I/O 密集型(网络、DB) |
📌 工程建议:
- 所有动态分配 → 用
make_unique/make_shared- 所有线程 → 用
jthread或协程- 所有共享状态 → 用
atomic或mutex+scoped_lock
5. 总结 & 下一篇预告
现代 C++ 的核心哲学是 "零成本抽象" + "资源即对象":
- 智能指针 → 内存安全
- RAII 线程 → 生命周期安全
- 协程 → 异步逻辑清晰化
你不需要成为语言专家,只需遵循这些模式,就能写出安全、高效、可维护的工业级代码。
✨ 下一篇预告 :
《【后端】【C++】从 epoll 到 io_uring:Linux 高性能网络编程的终极演进》我们将用 C++20 协程封装 Linux 最新 I/O 接口
io_uring,打造单机百万并发服务器!
6. 参考资料 & 往期文章
- 【后端】【C++】智能指针详解:从裸指针到 RAII 的优雅演进
- C++ Core Guidelines
- cppreference.com
❤️ 如果你觉得本文有价值,请点赞、收藏、转发!
欢迎在评论区讨论:你们公司还在用 VC++6.0 吗? 😅
✅ 编译提示 :所有 .cpp 文件需用 C++20 标准 编译。
✅ 代码结构 :各 .cpp 示例,可直接复制运行。
如需我扩展 协程调度器实现 、无锁队列示例 或 异常安全分析,请随时告诉我!