C++ unordered_map与unordered_set详解:哈希表原理、接口用法与性能优化
用过 C 的都知道当你还在用map、set做查找和去重的时候数据量一旦上来心里多少会有点不踏实。这时候就该unordered_map和unordered_set登场了。这两个容器在 C11 里正式进入标准库核心卖点就一句话基于哈希表实现把按 key 查找这件事从红黑树的 O(log n) 拉低到理论上的 O(1)。也就是数据越多优势越明显。这篇博客不绕弯子直接围绕unordered_map和unordered_set的介绍、接口使用、错误示范、典型坑位来做一次完整梳理。不管你是刚学 STL 的新手还是项目里已经用到但被隐性问题折磨过的老手都应该能从里面掏出点东西。1. 先说清楚为什么要用无序容器1.1 老牌 map/set 到底差在哪map和set底层是红黑树一种自平衡二叉搜索树。维护有序性是它们的优点遍历拿到的键天然就是排好序的。但代价也摆在那里每次插入和查找都要从根节点开始沿着树做一次 O(log n) 的寻路。当数据量到百万、千万级别log n 可能是 20 甚至 30 次比较每一次比较还可能伴随缓存未命中整体耗时非常可观。unordered_map/unordered_set的思路则完全不同先用一个哈希函数把 key 映射到一个桶的编号直接定位到桶这一层然后只在桶里做小范围查找。如果哈希函数质量正常、冲突不严重平均复杂度就是 O(1)。用生活里的事来类比红黑树相当于在一栋没有索引的大楼里按门牌号挨层找房间哈希表则是给你一张楼层索引卡直接告诉你坐哪部电梯到哪层。差距不是常数级是数据结构层面的代差。1.2 两个容器的定位差异unordered_map存的是键值对类似字典key-value 一一绑定unordered_set只存 key 本身类似一个数学上的集合核心用途是去重和存在性判断。源码实现上可以简单粗暴地理解成unordered_set的哈希节点里多绑了一个 value就变成了unordered_map。所以选型规则也很简单只需要知道这个东西有没有出现过用unordered_set需要根据 key 取出对应的附属信息用unordered_map。1.3 它们和原版 map/set 的 API 兼容性STL 设计者在接口层保持了高度一致insert、erase、find、count、size、empty、clear这些方法几乎长得一模一样。你用熟了map上手unordered_map基本零成本最大的差别只有两点一是它不保证内部元素顺序任何时候遍历出来的顺序都不是插入序也不是排序序二是unordered_map也支持operator[]但行为上有个隐藏陷阱后面专门说。这种接口继承让老项目从map切换过来非常平滑但注意平滑不代表正确切换之后依赖有序性的代码会立刻出错。2. unordered_map 接口实操与细节2.1 插入数据的四种方式直接看一段最常用的代码场景——统计一篇文章里每个单词出现的次数#include unordered_map #include string #include iostream int main() { std::unordered_mapstd::string, int wordCount; // 方式1operator[] 不存在时自动插入默认值 0 wordCount[hello]; // 方式2insert 插入 pair wordCount.insert(std::make_pair(world, 1)); // 方式3emplace 构造参数避免临时对象拷贝 wordCount.emplace(cpp, 1); // 方式4初始化列表 std::unordered_mapstd::string, int other {{a, 1}, {b, 2}}; return 0; }insert和emplace的区别值得说透一点。insert接收的是一个已经构造好的pair哪怕这个 pair 是临时产生的中间也会有构造、移动甚至在某些实现里还有额外拷贝。emplace则直接把构造参数透传给节点在哈希表内部原地构造省掉一层拷贝。对于string这种重类型的 keyemplace的收益是实打实的。我实测过大规模插入 100 万个字符串键值对用emplace比insert明显快时间差距大概有 15% 到 20% 的样子。另外别忽略返回值处理auto result wordCount.insert({cpp, 1}); if (!result.second) { std::cout key already exists, value result.first-second \n; }insert返回一个pairiterator, boolsecond为 false 说明键已存在此时不会覆盖原值而是返回已存在节点的迭代器。这是一个非常实用的判断手段。2.2 operator[] 和 at() 的行为差异这两个接口表面看着像行为差很远。// 如果 key missing 不存在operator[] 会创建一个默认值并插入 int v m[missing]; // 如果 key missing 不存在at() 会抛出 std::out_of_range 异常 int v2 m.at(missing);最典型的坑就在这里很多新手想判断一个 key 是否存在顺手就写了if (m[key] something)。这一写不存在的 key 就被创建出来了容器凭空多了元素后续的逻辑全乱了。正确做法是find或者count。而想要安全读取用at()至少能第一时间暴露键不存在的问题而不是悄悄塞一个 0 进去。2.3 查找与统计find 和 count 怎么选在unordered_map里find和count都能判断键是否存在。count在普通 map 中还可以统计重复键数量但在unordered_map中因为键唯一返回值只有 0 或 1逻辑上没问题但有些实现里count的调用路径和find不完全一致尤其是当我们要同时用到是否存在和对应的值时一定要用find一次拿到迭代器避免查两次auto it m.find(key); if (it ! m.end()) { // 用 it-second 拿值 } else { // 不存在 }这个习惯养成了对多线程环境下缩小查锁范围、减少重复查找都有好处。2.4 遍历删除的正确姿势删除操作里最容易踩坑的是在循环中删元素。直接erase(it)之后用it在大多数 STL 实现里看起来能跑但这是未定义行为换成某些标准库实现就直接崩了。规范写法是for (auto it m.begin(); it ! m.end(); ) { if (it-second 0) { it m.erase(it); // erase 返回下一个有效迭代器 } else { it; } }erase(it)返回被删元素的下一个迭代器这个特性是从 C11 开始标准化的使用时放心。另外按 key 删除erase(key)返回的是被删元素个数因为unordered_map键不重复返回值只有 0 或 1可以用来判断删除前到底有没有这个键。3. unordered_set 实战去重、存在性判断与集合运算3.1 经典去重从 vector 到 unordered_setunordered_set最朴素的用法就是去重。比如从一份带重复 ID 的列表里抽出不重复的集合#include unordered_set #include vector std::vectorint ids {1, 2, 2, 3, 3, 3, 4, 5}; std::unordered_setint uni(ids.begin(), ids.end()); ids.assign(uni.begin(), uni.end()); // 原数组去重后的结果这里有几个细节值得注意。uni构造完成后内部无序如果业务上要求最终输出顺序和第一次出现的顺序一致那unordered_set不满足得用vector手动配合unordered_set做先判断再插入或者干脆用set。去重不算完还要考虑主键的语义这里去重的是简单 int如果是自定义对象那必须同时提供哈希函数和相等比较器这在后面第 4 章展开。3.2 存在性判断白名单和首次出现标记很多系统的核心逻辑其实就是一句这个值我见过没有。比如网关过滤重复请求、日志分析统计独立用户、缓存系统做缓存键自查。unordered_set在这种场景下是很好的数据结构。std::unordered_setstd::string seen; bool firstAppear(const std::string id) { if (seen.find(id) ! seen.end()) { return false; } seen.insert(id); return true; }这段代码背后的效率逻辑是一次哈希计算 一次插入全程 O(1)。相比之下如果用一个vector做线性扫描同样的操作要 O(n)数据量一大就是灾难。当然这里有个隐患seen占用内存会持续增长如果系统里 ID 上不封顶就还得引入过期机制或者 LRU但这属于工程架构层面的问题容器本身是无辜的。3.3 面试常考自己实现交集、并集标准库没有给unordered_set直接提供求交集和求并集的接口但维护起来太简单了。求交集的做法是遍历较小的集合拿元素去较大的集合里findstd::unordered_setint a {1, 2, 3, 4, 5}; std::unordered_setint b {3, 4, 5, 6, 7}; std::vectorint common; for (int x : a) { if (b.find(x) ! b.end()) { common.push_back(x); } }求并集更简单把两个集合全部插入一个新的unordered_set就行。实际开发中我一般会先判断两个集合的大小固定遍历小的、查大的循环次数由小的那个决定整体性能更稳定。这个习惯在数据量悬殊时尤其重要。4. 自定义类型的哈希支持很多问题的根源4.1 什么是可哈希类型unordered_map和unordered_set默认能处理的基础类型包括整数、浮点、指针、std::string等因为标准库为它们提供了std::hash的特化版本。但你的业务结构体、自定义类默认是没有哈希函数的。试着把一个自定义struct直接塞进unordered_set编译器会吐出一大串错误核心信息通常是没有匹配的哈希函数可调用。很多人第一次看到这段报错会懵其实根本原因就是我这里说的类型不可哈希。4.2 自定义哈希函数和相等的标准写法要让自定义类型放进unordered_set需要同时提供两个东西哈希函数和相等比较器。相等比较器通常可以直接复用operator哈希函数则必须自己写。一个标准的例子struct Person { std::string name; int age; bool operator(const Person other) const { return name other.name age other.age; } }; struct PersonHash { size_t operator()(const Person p) const { // 使用标准库单值哈希进行组合 size_t h1 std::hashstd::string{}(p.name); size_t h2 std::hashint{}(p.age); // 把两个哈希值合并避免单纯异或导致相同值抵消 return h1 ^ (h2 0x9e3779b9 (h1 6) (h1 2)); } }; std::unordered_setPerson, PersonHash people;这里的哈希组合不是玄学。如果你直接写return h1 ^ h2;那么当两个不同字段组合恰好异或结果相同时冲突率会显著上升。上面那串常量0x9e3779b9是黄金分割比例的近似值被广泛用在布隆过滤器、哈希表扩容等场景中作用是打散数值分布。这种风格组合出来的哈希值比简单的相加、异或质量高一截。4.3 哈希不变性与相等的一致性约定写自定义哈希时最容易被忽略的一条原则两个相等的对象它们的哈希值必须相等。如果哈希函数和operator不一致会出现非常诡异的现象find明明应该找到某个元素却因为哈希值不同而直接跳到另一个桶永远找不到甚至同一个对象插入两次都不被认为重复。我曾经在一次故障排查里遇到过这种问题最后定位到是某段代码在比较两个对象时用了不同的字段集合而哈希函数用的又是另一套字段等于容器里的钥匙有两套自相矛盾。所以维护一个铁律hash(a) hash(b)是a b成立的必要条件。4.4 优先写进结构体的成员哈希在 C17 之后很多项目开始用std::pair或std::tuple作为 key标准库在某些目标平台上一度没有为它们默认实现哈希跨平台代码不要依赖碰巧能编过。我自己写库的时候习惯给常用类型封装一个统一的makeHash工具函数谁都能调避免每个人都手写一套不知道对不对的合并逻辑。5. 底层原理哈希表的工作模型与关键参数5.1 桶数组 冲突链的结构哈希表的主体是一个连续数组每个数组元素叫一个桶每个桶里挂一条链表标准库常用单链表。插入元素时先用哈希函数算出size_t哈希值再对桶数量取模定位到某个桶然后在这条链表里查找是否已有相同 key。没有则挂到链表上。查找过程同理。所以查找复杂度 O(1)成立的前提是每个桶里的链表足够短。这个前提一旦破坏比如某个哈希函数把所有 key 都映射到同一个桶哈希表就会退化成一条超长链表查找复杂度变成 O(n)直接等同线性扫描。这也是为什么哈希函数的质量和桶的容量需要一起被重视。5.2 负载因子与扩容机制哈希表不是初始就开无限大的数组它会根据元素数量动态扩容。这里有一个关键概念负载因子。负载因子 元素个数 / 桶数量标准库默认的最大负载因子是 1.0。当元素个数接近或超过桶数量时哈希表会触发一次 rehash重新分配一个更大的桶数组把所有旧元素重新哈希、重新分布到新桶中。这个操作的时间复杂度是 O(n)因为每个元素都要重新计算桶位置。如果你不断向容器里插入数据它就会不断在某个阈值附近触发 rehash表现为插入突然卡顿一下。5.3 提前 reserve 消除扩容抖动知道了扩容的代价优化手段就呼之欲出了如果预先知道元素数量级直接reserve即可。std::unordered_mapstd::string, int m; m.reserve(1000000); // 预分配足够桶reserve(n)会把桶数量预先调整到足以容纳 n 个元素且不触发 rehash 的大小。实测往一个大容器里批量灌数据先reserve比不reserve能快出明显一截尤其是在数据量超过百万之后rehash 导致的停顿和不连续内存分配会拖慢整个流程。这个动作代价小、收益大是最容易被忽视的高阶优化。5.4 用 bucket 接口诊断哈希质量标准库暴露了一组桶相关接口平时用不到但排查问题很关键size_t cnt m.bucket_count(); // 桶的数量 size_t len m.bucket_size(i); // 第 i 个桶里元素数量 size_t b m.bucket(key); // 某个 key 会落到哪个桶当我怀疑某个自定义哈希函数分布不均匀时会写一小段统计代码遍历所有桶找出最长的一条链表。如果某个桶里面挂了上百个元素而其他桶基本空着说明哈希函数质量很差典型的可能是因为取模对象的低位相同导致大量冲突。这时候换个哈希函数或者调整组合方式效果立竿见影。5.5 迭代器失效的规则容器操作时迭代器何时失效很多人记忆混乱。这里把规则说清楚插入单个元素时如果没触发 rehash只有该元素自身对应的迭代器可能失效其他迭代器不受影响。插入操作一旦触发 rehash所有迭代器都会失效但元素本身在内存中的地址不会变只是桶位置变了。删除一个元素只会让指向被删元素的迭代器失效其他迭代器统统不受影响。这条规则和vector完全不同vector只要插入就可能无效所有迭代器。哈希表的设计保证了在非 rehash 情况下迭代器稳定性很好做遍历插入的时候可以放心但仍要注意可能触发的 rehash 会破坏循环。6. 常见问题与排查技巧实录6.1 性能骤降先看冲突链再看扩容遇到unordered_map查找忽然变慢我先不看业务逻辑先统计每个桶的链长。如果发现某个桶链长几百问题定位到哈希函数如果整体桶数非常小、绝大多数桶都塞满了问题定位到容量没预留。处理方案对应两种自定义哈希函数换成更分散的组合式哈希批量插入前reserve。这两板斧打出去九成性能问题能解决。6.2 自定义结构体编不过检查三个点编不过的错误信息虽然长排查顺序很固定第一确认类型定义了operator第二确认哈希函数定义了operator()且返回size_t第三确认模板参数里第二个传的是哈希器类型。顺序反了、少写一个都会报错。这里有个技巧unordered_set的模板参数顺序是Key, Hash, KeyEqual, Allocator不能拿自定义相等比较器直接塞到第三个参数除非同时实现一个operator()比较器并传入第三个参数。6.3 误用 operator[] 导致数据被污染这个坑在线上环境特别阴险。日志分析时写了一句if (m[url] )用来判断空值结果日志里没出现的 URL 全部被插进m内存和统计结果双双爆炸。修法很简单把改成find或at()。排查这类问题的时候用m.size()和日志总条数对比一下一旦发现容器元素比日志条数还大基本就是 operator[] 的锅。6.4 内存占用比预想高哈希表的桶数组是连续内存而且为了保证低冲突率负载因子会维持在大约 1.0这意味着至少一半的桶可能处于空闲或半空闲状态。存 10000 个元素桶数量可能是 16384 甚至更多每个桶本身开销不大但桶数组一次性分配加上链表节点自身还有指针开销整体内存比vector高出一截。对内存敏感的场景建议评估一下是否可以用有序数组加二分查找替代。数据不频繁增删时一个排序的vectorstd::lower_bound在缓存命中率和内存占用上往往比哈希表更好。6.5 线程安全的误区STL 的unordered_map和unordered_set不是线程安全的这和 de facto 的期望一致。多线程同时insert写同一个容器轻则数据不一致重则直接崩溃。但加锁不是唯一答案读多写少时用std::shared_mutex让多线程并发读、写线程独占吞吐量高很多写密集时考虑分片设计或者用std::deque 锁池自己做分片哈希。我的建议是先把单个容器线程安全这个问题拔高到整个并发方案设计而不是在一个哈希表上缠斗。6.6 遍历时修改键值的基本禁忌unordered_map和unordered_set的 key 是 const 的正常手段改不了。想改 key 的标准姿势是erase掉旧元素再emplace新元素。千万别想着通过迭代器强转 const 去改 key那会让哈希表的桶位置信息失效之后查找、删除全部错乱属于未定义行为。很多面试题也会问这一点本质考的是对哈希表结构的理解。这篇内容从容器选型、接口实操、自定义类型支持一直到哈希表底层机制、性能排查、线程安全算是对unordered_map和unordered_set做了一次比较完整的梳理。写到最后我个人想强调的是两件事第一任何容器都要先理解底层数据结构再决定用不用哈希表的 O(1) 是建立在好哈希、好容量规划之上的不是无条件的第二操作接口的细节比想象中更重要operator[]的副作用和迭代器失效规则这种看着不起眼的知识点恰恰是线上事故的常客。我自己每次在项目里引入这批容器时都会在代码注释里顺手写上必须配合自定义哈希规则和 reserve 策略食用算是用血泪换来的备注习惯。

相关新闻

Linux新手第一周:环境搭建、常用命令与学习路线全记录

Linux新手第一周:环境搭建、常用命令与学习路线全记录

几个月前,社团面试的场景还在眼前,转眼第一周周报已经躺在群文件里。说实话,接手【西邮 Linux 兴趣小组】的第一周,我最大的感受不是“教了多少东西”,而是“被一群刚接触 Linux 的新人追着问问题,自己回头…

2026/10/10 14:08:50 阅读更多 →
踩坑实录:接进RAG后召回率反而崩了?all-MiniLM-L6-v2的5个隐藏陷阱

踩坑实录:接进RAG后召回率反而崩了?all-MiniLM-L6-v2的5个隐藏陷阱

踩坑实录:接进RAG后召回率反而崩了?all-MiniLM-L6-v2的5个隐藏陷阱 【免费下载链接】all-MiniLM-L6-v2 项目地址: https://ai.gitcode.com/hf_mirrors/sentence-transformers/all-MiniLM-L6-v2 把 all-MiniLM-L6-v2 接进 RAG 管线,几…

2026/10/10 14:08:50 阅读更多 →
2026年AI Agent发展趋势与挑战:从理论到实践的跨越,TaoToken统一Key打通OpenClaw落地链路

2026年AI Agent发展趋势与挑战:从理论到实践的跨越,TaoToken统一Key打通OpenClaw落地链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 14:08:50 阅读更多 →

最新新闻

统一登录与单点登录实战:网关与认证中心的搭建全解

统一登录与单点登录实战:网关与认证中心的搭建全解

这段时间我一直在折腾一件事:把我们内部几个各自为战的业务系统,统一到一个登录入口底下。项目代号倒是很形象,sward 负责守门,soular 负责认人。说白了,sward 是一个网关层,soular 是一个身份认证中心&…

2026/10/10 14:52:58 阅读更多 →
打印机驱动下载安装完整指南:从官网获取到故障排查

打印机驱动下载安装完整指南:从官网获取到故障排查

1. 打印机驱动安装这件事,为什么值得单独写一篇完整指南打印机驱动下载安装,听起来像是电脑入门级别的操作,但实际工作中我见过太多人在这上面翻车。有人下载了错误的驱动版本导致打印机频繁脱机,有人装完驱动后扫描功能死活调不出…

2026/10/10 14:52:58 阅读更多 →
基于SpringBoot+Vue+MySQL的船舶监造管理系统实战解析

基于SpringBoot+Vue+MySQL的船舶监造管理系统实战解析

做船舶监造的人肯定都懂,监造不是坐在办公室看看图纸就行,真正业务一铺开,报验单、现场见证、NCR整改闭环、试验计划、图纸送审,每个环节都是需要“有人跟、有记录、有闭环”的。早几年我在船厂和监造组干活时,全靠Exc…

2026/10/10 14:52:58 阅读更多 →
Zen Cart PayPal跳转插件:解决掉单与IPN异步通知问题

Zen Cart PayPal跳转插件:解决掉单与IPN异步通知问题

简介:面向ZenCart商城的PayPal跳转插件,用于打通ZenCart与PayPal支付接口,实现用户在付款时从商店页面到支付网关再返回结果页的完整跳转流程,适合使用ZenCart开展跨境或外贸电商的商家、开发者及运维人员。该插件压缩包共24个文件…

2026/10/10 14:52:58 阅读更多 →
线程池线程数配置实战:CPU密集型与IO密集型任务调优策略

线程池线程数配置实战:CPU密集型与IO密集型任务调优策略

1. 先分清任务在“算”还是在“等”——这是所有配置的起点1.1 CPU 密集型和 IO 密集型的本质差异多线程编程里有一个被问得最多的问题:线程池到底配多少个线程?我几乎每一次都会先反问他一句:你的任务是 CPU 密集型还是 IO 密集型&#xff1…

2026/10/10 14:52:57 阅读更多 →
Windows下OSGeo4W安装PDAL避坑指南:从环境配置到LAZ v1.4实测

Windows下OSGeo4W安装PDAL避坑指南:从环境配置到LAZ v1.4实测

简介:本资源是面向GIS开发者、遥感工程师及三维点云处理从业者的PDAL库离线安装包,专为解决Windows环境下因网络限制导致OSGeo4W官网下载PDAL失败或缓慢的痛点。压缩包完整封装了OSGeo4W64 64位安装环境及PDAL核心组件,并预集成CloudCompare兼…

2026/10/10 14:51:56 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →