今日看丁香园发的一篇文章,里面提到:
多数安眠药会非常苦。有些苦不是本身产品自带的,也不是我们不能把它添加各种味道,包裹各种东西去遮味,而是我们希望提醒使用者:你正在做这件事,正在吃一些特殊的东西。
其实在程序设计里也会采取类似的策略,这里分享下自己的想法。
简单抽象丁香园那篇文章提到的逻辑:有时候我们需要通过一些设计,防止某项东西被有意或者无意地滥用。比如文中提到的教授认为,我们应该放着安眠药药的苦性不管,这就是为了提醒吃药的人你正在吃药,而不是在吃什么无害的东西。
在我最近做的一个项目里也有一个类似的设计:我需要做一个用于unique_ptr
的dynamic_cast
。当然理论上下面这么设计是可以的:
1 | std::unique_ptr<Base>up1=std::make_unique<DerivedA>(),up2=std::make_unique<DerivedA>(); |
但是这样会很繁琐,因为:
- 在做移动赋值时我们需要写两遍参数
DerivedA
。 - 我们必须在每一个位置都手动写一个判断语句来判断是否转化成功。
因此选择抽象成一个函数,具体如下:
1 | template<typename To, typename From> |
这里值得注意的是,我参数类型用的是&&
,也就是右值引用。这里使用左值引用在语法上其实没有任何问题:
1 | template<typename To, typename From> |
甚至在写的时候可以省下一个std::move
,但是我还是选择了使用右值引用。这里其实就是丁香园那篇文章提到的“限制性使用提醒”:我要求我自己(和其他项目成员)显式地使用std::move
,来提醒自己,这里已经发生了一次所有权转移。有经验的开发者只要看到了std::move
就能马上看出来发生了所有权转移,但是“调用了dynamic_cast_uPtr_lvalue_ref
就会发生所有权转移”这种逻辑不一定能第一时间转过来。
你应该给自己的代码戴上镣铐,来防止它被滥用、乱用。
题外话:“给安眠药加苦味剂”这事本身可能没那么可信——我Google了“限制使用提醒”、“安眠药为什么苦”、“故意做成苦的”都没有找到相关内容,且专门去找文章作者问了下,文章作者也没有给出有力的证据。
不过这和这个说法本身具有启发性倒也不冲突就是了。
另一个题外话就是,在我的例子里,如果cast失败就直接assert掉程序,所以不需要考虑”A指针已经被释放但是B指针没有拿到导致内存泄漏”的问题。
- 本文作者: ChrisLee
- 本文链接: https://ipchrislee.github.io/2022/06/15/限制性使用提醒/
- 版权声明: This article is licensed under a Creative Commons Attribution 4.0 International License. Code sippets may be used under the MIT Licence.