[RE2] Regexp对象 | shared_ptr | AST树
第2章:Regexp(正则表达式对象)
欢迎回来
在第1章:RE2(API)中,我们了解到RE2类是C++中处理正则表达式的主要工具。
但当传入类似"(\\d+)-(\\d+)-(\\d+)"的模式时,RE2内部究竟如何"理解"这个字符串?
这就是**Regexp(正则表达式对象)**的职责所在——它是正则模式处理流程中的首个关键环节
Regexp解决什么问题?
想象你向建筑师描述梦想中的房屋。在施工前,建筑师需要绘制蓝图——这不是实体建筑,而是包含墙体位置、房间数量和屋顶类型等细节的结构化方案。
在re2中,正则表达式字符串(如a+b*c)就是原始描述,而Regexp对象则是经过解析的、机器可理解的结构化蓝图。当调用RE2 phone_pattern("...")时,RE2对象通过内部解析器将字符串转换为Regexp对象,明确表达:
- 哪些部分是字面量(如
a、b、c) - 哪些部分是重复操作(如
+表示"至少一次",*表示"零次或多次") - 这些部分如何组合(如拼接
abc或选择a|b) - 捕获组
(...)或字符类[...]等特殊结构
这种结构化表示使得后续的优化和编译更加高效。
Regexp:内部蓝图
前文传送:[OP-Agent] docs | Rego策略语言 | AST语法树
Regexp对象本质上是抽象语法树(AST)。以简单模式(a|b)c为例,其Regexp结构如下:

Regexp对象核心特性:
- 不可变性:创建后结构固定,确保线程安全
- 引用计数:通过计数机制共享对象,避免内存泄漏
🎢引用计数技术原理
引用计数通过为每个对象维护一个计数器,记录当前被引用的次数
-
当对象新增引用时计数器加1,释放引用时减1。计数器归零时自动释放对象内存
-
若存在循环引用(如A引用B,B又引用A),计数器无法归零会导致内存泄漏。
shared_ptr的设计:
shared_ptr采用引用计数实现智能内存管理
- 构造函数递增目标对象计数
- 析构函数递减计数并在归零时销毁对象
- 支持拷贝构造/赋值操作,自动维护引用计数
循环引用解决方案:
使用weak_ptr打破循环引用链:
- weak_ptr不增加引用计数
- 通过lock()临时获取可用的shared_ptr
- 典型场景:父子对象互相持有
weak_ptr而非shared_ptr
相关前文传送:
-
[蓝牙通信] 事件管理 | 生产者-消费者模型 | weak_ptr.lock()
-
[C++11#48][智能指针] RAII原则 | 智能指针的类型 | 模拟实现 | shared_ptr | 解决循环引用
解析流程
用户通常不直接创建Regexp对象,而是由RE2在初始化时自动完成解析:

代码实现
关键代码片段(简化自re2源码):
1. RE2初始化时触发解析
// re2/re2.cc
void RE2::Init(absl::string_view pattern) {entire_regexp_ = Regexp::Parse(pattern, flags_, &status); // 核心解析调用
}
2. 字面量节点的创建
// re2/parse.cc
bool ParseState::PushLiteral(Rune r) {Regexp* re = new Regexp(kRegexpLiteral, flags_);re->rune_ = r; // 存储字符值stacktop_ = re; // 压入解析栈
}
3. 树结构遍历工具
// re2/tostring.cc
string Regexp::ToString() {ToStringWalker w(&result);w.WalkExponential(this, max_depth); // 安全遍历AST
}
总结
Regexp对象是正则表达式处理流程中的结构化中间表示:
- 将原始字符串转换为机器友好的树形结构
- 支持语法检查与优化预处理
- 为后续编译阶段提供清晰蓝图
下一章:Prog(编译程序)
