惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Palo Alto Networks Blog
P
Proofpoint News Feed
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
Recorded Future
Recorded Future
M
MIT News - Artificial intelligence
罗磊的独立博客
J
Java Code Geeks
月光博客
月光博客
F
Full Disclosure
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
U
Unit 42
WordPress大学
WordPress大学
A
About on SuperTechFans
C
Cyber Attacks, Cyber Crime and Cyber Security
SecWiki News
SecWiki News
Security Latest
Security Latest
C
Check Point Blog
C
CERT Recently Published Vulnerability Notes
小众软件
小众软件
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
V
Visual Studio Blog
博客园_首页
NISL@THU
NISL@THU
I
Intezer
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
The Register - Security
The Register - Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Latest news
Latest news
Project Zero
Project Zero
博客园 - 叶小钗
C
Cybersecurity and Infrastructure Security Agency CISA
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy International News Feed
博客园 - 【当耐特】
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
V
Vulnerabilities – Threatpost
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
lil_tea c++ 2026 style guide
lil_tea · 2026-06-20 · via 博客园_首页

lil_tea c++ 2026 style guide

本文使用 yoga air + wsl + ubuntu 26.04 + vscode 编写.

把所有 debug 完成, 我保证, codin 是我一辈子的朝圣.

这是我在开发和算竞都使用的代码风格.

部分借鉴自 the cherno, 部分借鉴自 google c++ style guide, 部分借鉴自 linux kernel coding style, 部分借鉴自 算法竞赛进阶指南.
因为我年纪大了所以已经忘记哪一条是从哪借鉴的了, 朋友们看到哪条觉得合理就用吧, 不合理的不用就好了.

总结一句话: 坚持 c like 特色指针主义道路, 以安全性换自由; 姓 bjarne 还是姓 graydon 的问题上我们要坚持 bjarne 领导, 坚持 k&r 的文化自信, 坚决杜绝 graydon 的糖衣炮弹.

think twice, code once. enjoy~

调试

最重要的当然是打印函数:

void	log(long line_num) {
#ifdef	lil_tea
	std::println(std::cerr, "line: {} | hey siri, play <hit`em up> please", line_num);
#endif
}

但是向量加法函数可以有新的办法了:

std::vector<long> add(const std::vector<long> &a, const std::vector<long> &b)
	pre(a.size() == b.size()) {	// c++ 2026 新特性, 见 [contracts](https://en.cppreference.com/w/cpp/language/contracts.html)
	std::vector<long> c(a.size());

	for (long x : std::views::iota(0, c.size()))
		c[x] = a[x] + b[x];

	return c;
}

用 contracts 配合 g++-16 -fcontract-evaluation-semantic=quick_enforce 就又可以让代码 fail fast 了.

代码框架

标识符

全部使用 snake_case, 和 STL 保持统一, STL 用 snake_case 那我也用.

这方面我和 bjarne 的意见相同, 可以在 bjarne stroustrup q&a2how do you name variables? do you recommend "hungarian"? 条目见到 bjarne 观点的详细陈述.

头文件

#include <bits/stdc++.h>, 或者直接用 import std.

不是说这个代码是竞赛专用, 只要 g++ 提供了就说明这个头文件是有意义的, 开发中使用也有很多好处, 增加的编译时间可以忽略不计.

有人说这个会引入一些符号, 这个要分两方面说:

  1. 函数名容易冲突. 你不 using namespace std 哪来的函数名冲突?
  2. 宏名容易冲突. 首先你应该少定义宏, 其次我不知道你为什么非要定义一个冲突的宏名, 再说了这里面定义的什么宏是你需要再定义一遍的?

而且我用这个头文件有个次要目的是为了避免我的代码被 msvc 编译, 因为我只能确定我的代码在类 unix 系统上不出错, windows 上出任何错误都有可能.

命名空间

禁止 using namespace std;.

推荐的有 using namespace std::literals;.

一般不要在代码里用宏.

这方面我和 bjarne 的意见再次相同, 可以在 bjarne stroustrup f&q2so, what's wrong with using macros? 条目见到 bjarne 观点的详细陈述.

例外情况是, 假如你叫李华, 你可以定义 -Dli_hua 表示你在 debug, 然后写:

void	log(long line_num) {
#ifdef	li_hua
	std::println(std::cerr, "line: {} | i`m not good at English", line_num);
#endif
}

常量

k_ 前缀来代表这是个常量, 能用 constexpr 尽量用, 否则用 const.

比如说:

constexpr long k_inf = 0x3f3f3f3f3f3f3f3fl;	// 用于最大值, 最小值直接用 -k_inf
constexpr long k_mod = 998244353;	// 用于取模
constexpr long k_max_vtx = 1l << 17;	// 用于顶点数量, 2^17 <=> 10^5

变量

尽量缩小变量的作用域, 比如 for 用的变量就尽量不要让作用域到 for 外面.

引用符号和指针符号紧贴变量, 如 tree *ld_const std::vector<long> &a.

在类型明确的时候可以用 auto, 需要明确类型的时候用类型名.

这个 明确 包括函数返回值的类型, 认为是明确的.

auto tuple = std::make_tuple(1, 2, 3);
auto x = std::move(y);
for (std::size_t x : std::views::iota(0uz, v.size()))
	std::println("{}", v[x]);

当然带权图遍历连边应该用结构化绑定:

for (auto [y, z] : x->to_)
	y->dfs();

如果要修改 (比如标记一条边) 就用引用:

for (auto &[y, z, delta] : x->to_)
	if (y->dfs())
		delta = 1;

全局变量

如果可能会被多个线程修改就加锁, 如果确定只会被单线程修改就不用加锁.

namespace 管理全局变量和对应的锁.

namespace	total {	// 实际变量名
long val;	// 占位变量名
std::mutex lock;
}

全局变量名不加 g_ 前缀, 查询或修改全局变量的函数名需要加 g_ 前缀.

函数

大多数函数的返回值应该只跟参数有关, 一个函数只做好一件事, 尽量不动全局变量, 动全局变量的函数的函数名需要加 g_ 前缀.

如果一个参数不变, 一定要加 const. 比如刚才那个向量加法函数.

如果两个参数指向的内容不会重叠, 一定要加 restrict. 优化的作用对我来说并不重要因我我信任 -O2, 但这样可以提醒我多次检查不要传入重叠的东西.

合理情况下可以用运算符重载.

引用符号和指针符号紧贴变量, 如果有 restrict 则写类似 long *restrict a, long *restrict b.

匿名函数

只能用于回调函数, 比如:

// std::vector<long> a
std::sort(a.begin(), a.end(), [](long x, long y) {
	return y < x;
});

很明显这个例子并不好, 完全可以用 std::sort(a.rbegin(), a.rend()) 一行搞定的事非要用匿名函数, 但这是为了演示匿名函数所以情有可原, 实际应用中最好是使用 std::sort(a.rbegin(), a.rend()).

main 函数

signed main, 可以是 signed main(int argc, char **argv) 也可以是 signed main(void), 根据需求来.

没有出错则 return 0, 否则 return 1.

无论是单纯存数据还是带有函数, 都用 class.

类变量

变量名后加下划线, 比如 ld_ tot_.

根据需要可以放 privatepublic, 不必全放在 private. 最好的例子是我用于处理图的类:

class	vtx {
public:
	std::vector<vtx*> to_;
	long dfn_, low_;	// for tarjan
	vtx *top_, *dear_mama_, *kid_;	// for 树链剖分

	void add_edge(vtx*);
	void dfs_tarjan(/*anything*/);
	void dfs1_hld(vtx*), dfs2_hld(vtx*);
};

vtx v[k_max_vtx];

类函数

根据需要可以放 privatepublic, 不必全放在 public, 最好的例子是线段树:

class	tree {
	std::unique_ptr<tree> ld_, rd_;
	long left_, right_;
	long val_, tag_;

	void push_up(void);	// 私有
	void push_down(void);	// 私有

public:
	tree(long, long, const std::vector<long>&);	// 公有
	void update(long, long, long);	// 公有
	long query(long, long, long);	// 公有
};

构造函数

非常推荐, 一定要用初始化列表. STL 容器可以初始化或不初始化. 智能指针见后文指针部分.

tree(long left, long right, const std::vector<long> &a)
	: left_(left), right_(right),
	val_(0), tag_(0) {
	if (left_ == right_) {
		val_ = a[left_];
		return;
	}

	ld_ = std::make_unique<tree>(left_, left_ + right_ >> 1, a);
	rd_ = std::make_unique<tree>((left_ + right_ >> 1) + 1, right_, a);

	push_up();
}

构造函数里为类变量区分 复制, 引用, 抢劫

复制是说你要给传入的 object 复制一份, 也就是 ld_ = new tree(*y->ld_).

引用是说你要引用传入的 object, 也就是 ld_ = y->ld_.

抢劫则很明显就是你要让传入的 object 失效, 也就是 ld_ = y->ld_, 注意一定要额外写一行 y->ld_ = nullptr, 或者直接写 ld_ = std::move(y->ld_).

析构函数

非必要不写, 让智能指针和 STL 自动释放, 如果有裸指针则在析构函数里以合理方式杀死.

重载运算符

非常推荐, 比如矩阵乘法, 重载运算符后可以方便的实现矩阵快速幂.

千万不要用 shared_from_this, 使用传入的 std::shared_ptr &const std::shared_ptr & 代替.

参数名建议叫 ref_this, 先判断:

if (ref_this.get() != this)
	std::terminate();

当然这里现在用 pre 会更方便了.

std::weak_ptr 的重载版本

比如说有 classx::work(std::shared_ptr<classx> &ref_this), 这时候我还会写一个重载的 classx::work(std::weak_ptr<classx> &ref_this).

内容很简单, 直接调用:

auto	work(std::shared_ptr<classx> &ref_this) {
	return work(ref_this.lock());
}

这里为什么我敢在 lock() 为空的时候也传入呢, 因为 lock() 为空的时候是通不过 if (ref_this.get() != this) 的检测的, 就炸了.

指针

到了最有意思的部分了.

我哥 3f 的指针哲学大多来源于 mycall, 而我的指针哲学部分来源于 一扶苏一女士 另外的来源于 the cherno.

裸指针

用于管理图论的顶点 (树论也属于图论).

尽量尽量尽量不要用裸指针存储 new.

因为图论是复杂的, 但又是不变的, 这恰好也是裸指针的优势, 所以我们这样写:

constexpr long k_max_vtx = 1l << 17;
class	vtx;
extern	vtx v[k_max_vtx];	// 提前声明, 后面就能判断了

class	vtx{
public:
	std::vector<vtx*> to_;

	void	add_edge(vtx *y)
		pre(v <= this && this < v + k_max_vtx && v <= y && y < v + k_max_vtx) {
		to_.emplace_back(y);
	}
};

vtx v[k_max_vtx];

关于 char **argv

我的习惯是这样:

signed	solve(const std::span<std::string_view>&);

signed	main(int argc, char **argv) {
	std::vector<std::string_view> tmp(argv, argv + argc);
	std::span<std::string_view> args(tmp);
	return solve(args);
}

很显然这是借鉴了 java 的 String[] args, 但 java 作为友军语言也是可以借鉴的优秀设计.

智能指针

独占指针

独占指针的语义是, 这个内容是你自己的.

很好的例子是线段树 / 平衡树, 你的孩子顶点肯定是你独占的, 所以我们用独占指针.

class	tree {
	std::unique_ptr<tree> ld_, rd_;
	// other
};

共享指针

共享指针的语义是, 这个内容是公有的.

很好的例子是持久化线段树, 你的孩子是继承的 / 修改的, 所以我们用共享指针.

class	tree {
	std::shared_ptr<tree> ld_, rd_;
	// other
};

弱指针

弱指针的语义是, 我还是个共享指针, 但是我不参与引用计数, 用于避免循环引用.

很好的例子是双链表.

class	list_vtx {
public:
	std::weak_ptr<list_vtx> pre_;
	std::shared_ptr<list_vtx> nxt_;
	// other
};

iso 和 cherno 认为的弱指针语义是, 这个对象可能活着也可能死了, 所以使用之前需要先检查. 但我不认同这个语义.

很显然刚才的双链表就是避免循环引用才用的弱指针, 你无需使用 if (pre_.lock()) 就能确定 pre_.lock() 是有效的, 如果无效则说明你的双链表是错误的 (当然了, 头顶点的 pre_ 就应该是空的, 而后面每个顶点的 pre_ 都应该是有效的), 而如果错了就会因为 pre_.lock() 为空而及时 fail fast.

删除顶点 x 直接 x->pop():

void	pop(void) {
	if (nxt_)	// 如果先修改 pre_->nxt_ 则会导致引用计数为 0, 所以先修改 nxt_->pre_
		nxt_->pre_ = pre_;
	pre_.lock()->nxt_ = nxt_;	// 头顶点不存数据, 所以存数据的顶点一定有 pre_
	// 引用计数为 0 自动删除, 会调用析构函数
}

杂项

缩进

使用 tab 可以让你的代码在不同的 ide 里可以按照不同人的喜好来缩进, 而使用空格会导致所有人看到的都是按照你的喜好进行的缩进.

我平时用的 8 字长 tab, 到了 mycall 的电脑上显示的是 2 字长, 这样我们两人看着都方便.

行长限制

我个人喜欢把行长限制为 1mol 个字长, 我觉得过分限制行长 (比如 80 字长) 是不好的 don quixote 风格.

在 1mol 字长限制的情况下, 一行的长度经常超出我的显示器, 那么我就会使用这个设置:

"editor.wordWrap": "bounded",	// 在屏幕宽度和代码行长限制的较小值处自动折行, 实际还在同一行
"editor.wordWrapColumn": 1073741824,	// vscode 最大行长限制
"editor.wrappingIndent": "same",	// 自动折行后维持相同缩进
"editor.wrappingStrategy": "advanced",	// 让 vscode 计算行长, 因为 tab 的字长不一定是 1 所以需要

运算符

二元运算符和三元运算符两边加空格, 比较美观, 没什么特别的用处. 一元运算符可加可不加.

如果一个地方你想要的优先级符合 iso 的优先级 那就不要加括号, 比如取中点你想要 \(\cfrac{left\_+right\_}{2}\) 就可以直接写 left_ + right_ >> 1.

额外的, 我还喜欢把 x > y 写成 y < x, 因为我不太喜欢大于号...

管道运算符

不要用, 不要用, 不要用.

如果你需要遍历一个集合, 你应该做的是先构造这个集合, 无论是 std::vector<long> euler_sieve(long max) 还是 std::views::iota(0uz, v.size()) 都是构造的方式.

但管道是个奇怪的东西, 管道的含义是先构造出一个全集, 然后用淘汰赛的方式选出你需要的集合. 我觉得这非常不明确, 不如直接构造出想要的集合.

goto 运算符

这是运算符吗? 反正我喜欢当成运算符.

可以适当使用, 当且仅当你是往下跳. 不要用来跳到函数最后统一释放资源因为资源应该让智能指针自动释放, 而是用于状态机的设计.

比如分块的区间求和:

long	query(std::size_t p, std::size_t q) const
	pre(p <= q && 0 <= p && q < a.size()) {
	std::size_t from = pos_[p], term = pos_[q];
	long yt = 0;

	if (from != term)
		goto qry_from;

	for (std::size_t x = p; x <= q; ++x)
		yt += a_[x] + tag_[from];
	
	return yt;

qry_from:
	if (from_[from] == p)	// 整块则当成整块
		goto qry_term;

	for (std::size_t x = p; x <= term_[from]; ++x)
		yt += a_[x] + tag_[from];

	from++;

qry_term:
	if (q == term_[term])	// 整块则当成整块
		goto qry_ssr;

	for (std::size_t x = from_[term]; x <= q; ++x)
		yt += a_[x] + tag_[term];

	term--;

qry_ssr:
	for (std::size_t x = from; x <= term; ++x)
		yt += sum_[x];

	return yt;
}

代码块

if 后空格再写条件, for 后空格再写循环描述, while 后空格再写条件, 禁用 switch.

因为 switch 没写 break 害我在基本算法单元测试里丢了 160 分.

if 里赋值是很常见的情况, 这时建议使用双层括号来明确语义, 比如说树剖的 dfs:

void	dfs_kid(vtx *_) {
	if ((dear_mama_ = _))	// if 里做赋值并判断
		depth_ = dear_mama_->depth_ + 1;
	else
		depth_ = 0uz;

	size_ = 1uz;
	kid_ = v;

	for (vtx *y : to_) {
		if (y->kid_)
			continue;

		y->dfs_kid(this);
		size_ += y->size_;

		if (kid_->size_ < y->size_ || kid_->size_ < y->size_ && y < kid_)
			kid_ = y;
	}
}

注释

行内注释使用 /**/ (不允许跨行), 行末注释使用 //.

枚举

推荐使用 enum class, 比如说我设计 game engine 的时候就有:

enum class color : long {
	red = 0xff0000,
	green = 0x00ff00,
	blue = 0x0000ff
};

这样就可以确保使用 color x = color::red 而不是 int x = color::red.