std::generator本质是协程封装,非迭代器替代品;它绕过繁琐迭代器接口,专注惰性生成与栈帧挂起,适用于递归遍历、分页拼接等场景,但不支持随机访问、多次遍历,且需注意suspend/resume开销及yield对象生命周期。

std::generator 本质是协程封装,不是迭代器替代品
它不简化传统迭代器编写,而是绕过迭代器——你不用手写 begin()/end()、operator++、operator* 这套繁复接口。底层仍依赖迭代器语义(返回 std::generator),但用户只需专注“怎么生成值”,而非“怎么被遍历”。
典型误用是试图把它当 std::vector 的轻量替代:它不支持随机访问、不保存全部元素、不可多次遍历。它的价值在「惰性生成 + 栈帧挂起」,比如递归树遍历、状态机流、分页数据拼接。
用 co_yield 写生成逻辑,比手写迭代器直观得多
传统迭代器需维护状态机(如当前节点指针、栈、是否已初始化),出错点密集;而 std::generator 允许用直白的同步风格写异步感逻辑。
- 递归遍历二叉树时,直接
co_yield root->val;,再递归调用自身,无需手动模拟栈 - 读取大文件按块 yield,可直接
while (file.read(buf)) co_yield std::string_view(buf, n);,不用拆成next_chunk()+ 状态字段 - 生成斐波那契数列:不用存前两项为成员变量,直接在协程栈上定义
int a = 0, b = 1;并循环co_yield a; std::tie(a, b) = std::make_tuple(b, a + b);
注意 suspend/resume 开销和 lifetime 约束
std::generator 对象本身轻量(通常只含一个指针),但每次 co_yield 会触发栈挂起,resume 时恢复局部变量——这比纯函数调用贵,不适合高频小粒度 yield(如每毫秒 yield 一个 int)。
立即学习“C++免费学习笔记(深入)”;
更关键的是 lifetime:yield 出的引用/指针必须指向协程栈外的对象。下面代码是危险的:
std::generatorbad_example() { std::string local = "hello"; co_yield local; // ❌ local 在协程挂起后已析构 }
正确做法是 yield 值拷贝、或确保所引对象生命周期长于 generator 实例(例如 static 变量、传入的 const 引用参数、堆分配对象)。
编译与标准库支持现状仍是硬门槛
截至 2024 年中,GCC 13+(需 -std=c++23 -fcoroutines)、Clang 17+(需 -std=c++23 -stdlib=libc++)、MSVC 19.35+ 支持,但 libstdc++ 尚未实现 std::generator(GCC 下需切换到 libc++ 或等待 GCC 14)。很多项目卡在 C++20,直接用 C++23 协程特性意味着放弃旧工具链。
另外,std::generator 不支持移动以外的赋值(无拷贝构造),且无法从范围适配器(如 views::filter)直接消费——你得先转成容器或手动循环,这点常被忽略。











