C++ 杂项讨论

目录

一、避免使用 handles 有其代价(Effective C++ 53)

什么是“Handle”(句柄)?

 为什么很多人喜欢用 Handle?

那为什么说“有代价”?(重要)

实例:值语义 vs Handle 语义

二、让自己熟悉包括 TR1 在内的标准程序库(Effective C++ 54)

TR1 是什么?

R1 / C++11 标准库有哪些重要东西?(你要会用)

为什么要熟悉 TR1(C++11 标准库)?

三、让自己熟悉 Boost(Effective C++ 55)

Boost 是什么?(一句话)

Boost 为什么这么牛?

Boost 适合用来干什么?

Boost 最大的价值是什么?

“Boost 入门实践建议表”

一、避免使用 handles 有其代价(Effective C++ 53)

要知道把对象封装在 Handle(句柄)中是有代价的。

什么是“Handle”(句柄)?

在 C++ 中 Handle 类指:

一个类内部只包含一个指针,
真正的数据存在堆里。

例子:

class String {
private:
    char* data;   // handle → 指向真正的对象
};

data 不是“字符串本体”。
data 只是一个“指针”(handle),
指向真正存放字符串的“内存区域”(真正的对象)。

String 对象本身:
┌──────────┐
│  data ---> ───────────────┐
└──────────┘                 │
                             ▼
                      ┌─────────────┐
                      │ 'H''i''\0'  │  ← 字符串真正储存在这里
                      └─────────────┘

也叫:

  • 指针语义(pointer semantics)

  • pImpl(pointer to implementation)

  • 智能指针(也算一种 Handle)

  • 句柄类(handle class)

换句话说:

Handle = 外面看起来像对象,内部其实是指针。

 为什么很多人喜欢用 Handle?

因为它有几个优点:

1)减少编译依赖(Pimpl)

.h 里只有指针,不包含真正实现 → 改动不会增量编译。

2)可以共享底层对象(引用计数)

多个 handle 指向同一个底层对象。

3)可以做到 copy-on-write

String 类曾经用过 COW。

4)可以隐藏实现细节(封装性强)

那为什么说“有代价”?(重要)

因为:把数据放在句柄里,而不是对象自身,就带来很多性能和语义成本。

代价 1:无法使用“值语义”,行为更像指针

我们写:

Widget a;
Widget b = a;

如果 Widget 是普通类,a 和 b 各有自己的数据。

但如果 Widget 是 Handle:

class Widget {
    Impl* p;
};

那么:

b.p = a.p;   // 两者共享同一个底层对象

看起来像拷贝,但“语义变了”,这是风险。

代价 2:多一次间接访问(慢)

访问字段需要:

w.p->value     // 比 w.value 多一次指针跳转

指针跳转会影响:

  • cache miss

  • 指令预测

  • 优化能力

普通对象:

value   // 直接访问

速度更快。

 代价 3:内存布局不连续

特别重要!

例子:

std::vector<Widget> v;

如果 Widget 是普通类:

  • v 的内存是连续的

  • CPU 预取很容易

  • 遍历速度极快

但如果 Widget 是 Handle:

  • vector 里其实是很多个指针

  • 指向的 Impl 在堆里乱七八糟,完全不连续

  • 遍历时 cache miss 爆炸 → 性能恶劣

代价 4:必须管理深拷贝 / 引用计数 / 复制控制

必须自己写:

  • 拷贝构造

  • 赋值运算符

  • 析构函数

要么深拷贝:

p = new Impl(*other.p);

要么引用计数:

++p->refcount;

要么使用共享机制:

  • 复杂

  • 容易出 bug

普通对象不需要这些。

代价 5:更多内存管理风险

因为必须手写:

  • new

  • delete

  • copy

  • move

一旦漏写 → 崩溃 / double free / 内存泄漏

小结

Handle 有好处,但代价是:
性能变差、复杂度上升、语义变模糊、容易出错。

“避免使用 handles 有其代价” 的意思是:

你选择不用“值语义”而使用“指针语义”,
你会付出性能、语义、正确性方面的成本。

实例:值语义 vs Handle 语义

普通(值语义)

class Point {
    int x, y;
};

复制:

Point b = a;   // 快,语义清晰

Handle(指针语义)

class Point {
    struct Impl { int x, y; };
    Impl* p;
};

复制:

b.p = a.p;     // 看似拷贝,实际共享

修改 b 会影响 a
完全不像“值拷贝”。

总结

Handle(句柄类)虽然减少编译依赖、便于封装,但代价是性能损失、结构复杂、语义变脆弱。
Effective C++ 提醒你:使用 Handle 是 trade-off,不是免费午餐。

二、让自己熟悉包括 TR1 在内的标准程序库(Effective C++ 54)

不要自己重复造轮子,标准库能做的事,就不要自己做。
熟悉标准库(包括 TR1 → 现代 C++ 标准库)能让你更高效、更安全、更少 bug。

TR1 是什么?

TR1(Technical Report 1)是 C++98 时代,标准委员会发布的一组“即将进入标准库的扩展组件”。

后来这些内容全部进入了 C++11,所以:

👉 TR1 = C++11 标准库的预览版

  • std::shared_ptr

  • std::function

  • std::bind

  • std::unordered_map

  • std::tuple

  • std::regex

这些全部来自 TR1。

所以 Meyers 的意思是:

必须熟悉 C++11 标准库(因为它就是 TR1)。

R1 / C++11 标准库有哪些重要东西?(你要会用)

1)智能指针(shared_ptr / weak_ptr / unique_ptr)

来自 TR1,如今是 C++11 标准库核心。

用途:

  • 做资源管理(RAII)

  • 避免内存泄漏

  • 避免双重 delete

  • 安全的对象共享

std::shared_ptr<Widget> p(new Widget);

2)函数包装器(std::function / std::bind)

替代函数指针,能存任何可调用对象。

std::function<int(int)> f = [](int x){ return x*2; };

很多人分不清函数包装器和句柄:

普通函数指针:       只能指向 ↓
     fp  ───────→ [普通函数]

函数包装器:         能指向 ↓
     std::function ─→ [普通函数]
                     [lambda + 捕获数据]
                     [std::bind 绑定后的对象]
                     [成员函数 + 对象实例]
                     [仿函数]
                     [任意可调用对象]

3)哈希表(unordered_map / unordered_set)

比 map/set 更快(哈希结构,不是红黑树)

std::unordered_map<std::string, int> m;

4)元组(std::tuple)

传递多个不同类型的数据的轻量容器。

auto t = std::make_tuple(1, "hi", 3.14);

5)正则表达式(std::regex)

标准库内置的正则。

6)随机数工具()

替代 rand(),质量更高。

7)类型萃取(type traits)

模板元编程的基础工具:

  • std::is_pointer<T>

  • std::is_integral<T>

  • std::remove_reference<T>

Effective C++ 在后面大量使用这些。

为什么要熟悉 TR1(C++11 标准库)?

因为:

✔ 它比自己写的更快

算法经过几十年优化。

✔ 它比自己写的更安全

例如 shared_ptr 自动释放资源,不泄漏。

✔ 它比自己写的更可移植

所有平台都支持。

✔ 它是现代 C++ 的基础

例如:

  • lambda

  • async

  • future

  • chrono

  • memory

  • algorithm

全部和这些组件紧密联系。

现代 C++ 的力量来自标准库,而不是语言本身。
会用标准库 = 会用 C++。

Effective C++ 不是让你背 API,而是:只要标准库能做,就不要自己写。

图总结

C++11 标准库 = TR1 + 更多东西
TR1 = 智能指针 + 哈希容器 + bind/function + tuple + regex + random + type_traits

Meyers 强调:

必须熟悉这些,否则会一直手写低效版的轮子。


能得到什么能力?

  • 少写 50% 代码

  • 少 80% bug

  • 性能更高

  • 和现代框架(Qt, Boost, LLVM)更兼容

  • 用标准方案而不是自家奇怪代码

保证在项目里( PTZ、WebRTC、模块管理、NetDetect 等)用到大量:

  • shared_ptr

  • unordered_map

  • bind/function

  • type traits

  • tuple

  • chrono

  • future/thread

  • etc.

三、让自己熟悉 Boost(Effective C++ 55)

Boost 是什么?(一句话)

Boost = C++ 世界最强的“第三方标准库”,
里面的东西后来大部分都进了 C++11/C++14/C++17 标准。

现代 C++ 想写好,Boost 必须熟悉。


Boost 为什么这么牛?

因为 C++ 标准库里好多东西都是从 Boost 抽进去的

Boost 组件

进入 C++ 标准库

shared_ptr

C++11 std::shared_ptr

weak_ptr

C++11 std::weak_ptr

function

C++11 std::function

bind

C++11 std::bind

thread

C++11 std::thread

regex

C++11 std::regex

chrono

C++11 std::chrono

unordered_map

C++11 unordered_map

tuple

C++11 std::tuple

random

C++11

type_traits

C++11 type_traits

现在用的很多现代 C++ 技术,都是 Boost 发明的。

Boost 适合用来干什么?

Boost 是一个巨大的库体系,涵盖:

 1. 高质量智能指针

  • Boost shared_ptr(标准库原始实现)

  • Boost intrusive_ptr

2. 容器和数据结构

  • Boost circular_buffer(环形缓冲区)

  • Boost multi_array(多维数组)

  • Boost flat_map(比 map 更快)

3. 字符串和正则

  • Boost string_algo

  • Boost regex(标准库 regex 的前身)

4. 文件系统

  • Boost filesystem(完全搬进 C++17 的 std::filesystem)

5. 网络编程(广泛使用)

  • Boost Asio(现代 C++ 网络编程标准)

    • TCP, UDP, SSL

    • 定时器

    • 协程 I/O

碎碎念:我的项目(网络设备、PTZ、WebRTC、网关)非常适合用 Asio。

 6. 日期与时间

  • Boost date_time(高精度时间)

  • Boost chrono(后进入 std::chrono)

7. 序列化(Serialize)

  • Boost Serialization(可以用来序列化对象)

 8. 多线程和并发

  • Boost thread(进入 std::thread)

  • Boost atomic(进入 std::atomic)

9. 数学与科学计算

  • Boost ublas(线性代数)

  • Boost multiprecision(大数)

  • Boost geometry(空间几何)

10. 模板元编程(TMP)神器

  • Boost MPL

  • Boost Hana(C++14 TMP 终极神器)

  • Boost TypeIndex / TypeTraits

Boost 最大的价值是什么?

(1)质量极高

Boost 的每个库都需要:

  • 设计审查

  • 标准委员会审核

  • 多平台测试

  • 严格代码质量

比大多数开源库靠谱得多。

(2)现代 C++ 的试验田

Boost 的许多功能会先在 Boost 成熟,然后进入标准库。

想学未来 C++ 的方向,看 Boost 就够了

(3)无依赖,纯头文件库

很多 Boost 库是 header-only(不需要编译、安装)。

现代 C++ 的许多高级技巧和能力标准库还没有,Boost 里都有。
若你不用 Boost,就等于错过了 C++ 的一半力量。

碎碎念:我的场景(嵌入式 + 网络 + C++ 工程)可以用以下库

(PTZ 控制、WebRTC、任务执行池、线程池、HTTP、设备管理、NetDetect)

✔ Boost Asio(网络编程)

比 libhv 更底层、更强。

✔ Boost optional(可选值)

C++17 的 std::optional 之前都靠它。

✔ Boost filesystem(文件系统)

跨平台,方便读写日志、配置。

✔ Boost circular_buffer(环形缓冲区)

用于视频流、日志 buffer。

✔ Boost type_traits / MPL / Hana

学模板 → boost MPL 是最好的学习参考。

✔ Boost lockfree

高性能无锁队列,多线程项目会用到。

“Boost 入门实践建议表”

级别

Boost 模块

为什么

入门

optional, regex, filesystem

最接近标准库,很好上手

进阶

asio, lockfree, circular_buffer

高性能网络和并发

高级

MPL, Hana, TypeIndex

模板元编程神器

实战

serialization, ublas

工程项目直接能用

总结

Boost = C++ 标准库的未来 + C++ 世界最大的“武器库”。
熟悉 Boost = 熟悉现代 C++。

它太重要了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值