所有权与智能指针

Share
没错,技术博主开始写技术文了

从我开始学C/C++的时候,指针和内存管理就是最让我头疼的东西:要么是忘了释放内存造成内存泄露,要么是多重释放造成了访问失败。甚至有些时候一个方法有多个返回语句的时候还要在每一个返回语句前释放一下内存。当时就在想为什么不能像Java一样有一个智能的垃圾回收器,来管理所有的内存呢。

这个痛点一直困扰到我开始学STL。原来STL早就考虑到手动释放内存的繁琐,所以提供了多种智能指针:auto_ptr, unique_ptr, shared_ptr, weak_ptr,并引入了“所有权”这个概念。大大简化了工程项目中的内存管理。也让我意识到我学的是假C++,真C(菜)。

所有权

单一所有权

两句话:所有权的拥有者有义务释放内存或转移所有权。同一时刻只会有一个所有权拥有者。

共享所有权

和用裸指针一样,所有权的拥有者不必负责释放内存,引用计数器会负责释放内存。同一时刻可以有多个所有权拥有者。

unique_ptr

重要的事情说三遍:

unique_ptr 不能被拷贝

unique_ptr 不能被拷贝

unique_ptr 不能被拷贝

unique_ptr 的所有者即为单一所有权的拥有者,因此它无法被拷贝。如果需要转移所有权,需要显示调用 move(unique_ptr) 来转移 或者 unqie_ptr.release() 方法放弃所有权。在生命周期结束时,若 unique_ptr 依然是所有权的拥有者,它会立刻释放掉对应的资源。示例:

unique_ptr<A> a = make_unique<A>();
unique_ptr<A> b = a; // can not assign unique_ptr to other unique_ptr
unique_ptr<A> c(a);  // can not copy unique_ptr
unique_ptr<A> d(a.release()); // OK, a release the resource
unique_ptr<A> e = move(a); // OK, a transfer ownership to e

与裸指针不同,单一所有权明确了资源的所有者,确定了资源该于何时被释放,增强了代码的可读性。当然,传递 unique_ptr 引用这种合法不合理的事也别干,要么直接 move 过去,要么只提供 unique_ptr.get() 但不转移所有权。

小惊喜:试试 std::set<unique_ptr>,有惊喜。

shared_ptr

shared_ptr 在使用上更像裸指针,不同的地方就是它内部有一个引用计数器,记录了有多少共享所有权的拥有者。当计数归零,它会自动释放掉资源。它的优势是比 unique_ptr 更灵活,在很多需要共享资源的场景(比如多线程共享物件),它符合场景的需求。并且活用 shared_ptr最后走的人关门特性,在某些多线程应用的场景里可以实现会话结束通知,更新标记等功能。

彩蛋:

const unique_ptr<T> & make the world a better place

Read more

低绩效同事,先别急着下结论

低绩效同事,先别急着下结论

团队里最难处理的,往往不是最差的同事,而是那些卡在board line上,挤挤能出活、但不挤就磨洋工的low performer 同事。 这类 low performer 一出现,很多Manager的第一反应就是:ownership 不行。问题是,这句话太空了,空到几乎没法行动。 我更喜欢用一个简单的框架看这件事:先判断原因,再调整支持,接着设观察期,最后做去留决定。 先判断:到底是哪一类问题 low performance 不等于 low ability。常见情况其实不一样: * 不会做:能力还没到,拆问题、推进、沟通都卡住。 * 不想做:知道怎么做,但投入不够。 * 做错方向:很努力,但目标理解偏了。 * 岗位不匹配:人不差,只是不适合这个角色。 比如: * 一个同事总是晚交,但每次都能把问题讲清楚,可能是任务切太大了。 * 一个同事总返工,

By andy

Vibe coding 之踩坑记

Vibe coding 对于程序员的技能要求反而比之前高了 先讲一个故事。 我这几天突然被隔壁组叫去,帮他们解决一个支付系统的问题。 简单来说,我们的客户分成机构和下属的医疗场所。一个机构下面可能有多个场所,然后机构可以统一管理下属场所的账单,支付等等。这样就需要我们能在我们的支付系统里面建立一个关系树,让父结点能看到子节点的账单,并支付。 问题就出在这个关系树上。因为我们之前用过一个另外的支付系统,所以有一部分老客户是从之前的系统迁移过来的。 这个老系统给每个客户创建了一个独特的id,但是这个id 和我们内部使用的id 并不一致,所以我们需要自己把客户的id 和他们的支付账户连接起来。然而: * 新的支付系统只支持固定的一些属性进行搜索。所以之前做这个项目的工程师A耍了个小聪明,用客户的last-name 属性存储了我们的id * 第一个雷:用户的last-name是可以由用户自行修改的。如果他们修改了,我们的对应关系就乱套了。 * 但是这个id A存错了,应该存储机构的id,A存成了下属场所的

By andy

关于flashblocks

争取整个短文系列,迎合短视频的潮流。 base前段时间整了个活,提出了一个新的概念叫flashblocks。 在有flashblocks之前,每个区块的状态是要么这个区块还不存在,没法拿到区块的任何状态和信息;要么就是这个区块已经存在了,它的状态是不可变的,拿到就是最终区块。base链每2秒产生一个新的区块,即任何的交易需要2秒钟才能确认。 如下图,区块A生成之后,2秒内用户只能看到区块A,直到区块B生成。 flashblocks呢,它允许用户提前获取正在打包的区块的状态。正在打包的区块每200ms更新一次状态,直到10次更新之后,正在打包的区块变成一个完整的区块。 如下图,区块A打包200ms后,用户可以立刻看到区块B的状态0. 再200ms后,可以看到区块B的状态1,直到区块B的状态9,然后区块B稳定,开始生成区块C的状态1。 flashblocks的好处是什么呢?它可以在一个区块完全打包好之前,让用户提前知道自己的交易是否有被打包进当前的区块,加速交易状态的确认。 缺点又有哪些呢? 首先这个确认属于预确认(preconfirmation), 这个预确认还没有状态更新

By andy