当前位置: 首页 > news >正文

The “Rule-of-Zero“ should be followed (s4963)

Most classes should not directly handle resources, but instead, use members that perform resource handling for them:

  • For memory, it can be std::unique_ptrstd::shared_ptrstd::vector…​
  • For files, it can be std::ofstreamstd::ifstream…​
  • …​

Classes that avoid directly handling resources don’t need to define any of the special member functions required to properly handle resources: destructor, copy constructor, move constructor, copy-assignment operator, move-assignment operator. That’s because the versions of those functions provided by the compiler do the right thing automatically, which is especially useful because writing these functions correctly is typically tricky and error-prone.

Omitting all of these functions from a class is known as the Rule of Zero because no special function should be defined.

In some cases, this rule takes a slightly different shape, while respecting the fact that no definition of those functions will be provided:

  • For the base class of a polymorphic hierarchy, the destructor should be declared as public and virtual, and defaulted (=default). The copy-constructor and copy-assignment operator should be deleted. (If you want to copy classes in a polymorphic hierarchy, use the clone idiom.) The move operation will be automatically deleted by the compiler.
  • For other kinds of base classes, the destructor should be protected and non-virtual, and defaulted (=default).

Noncompliant Code Example

class FooPointer { // Noncompliant. The code is correct (it follows the rule of 5), but unnecessarily complexFoo* pFoo;
public:FooPointer(int initValue) {pFoo = new Foo(initValue);}~FooPointer() {delete pFoo;}FooPointer(FooPointer const &fp) = delete;FooPointer const & operator=(FooPointer const &fp) = delete;FooPointer(FooPointer &&fp) noexcept {pFoo = fp.pFoo;fp.pFoo = nullptr;}FooPointer const & operator=(FooPointer &&fp) {FooPointer temp(std::move(fp));std::swap(temp.pFoo, pFoo);return *this;}
};

Compliant Solution

class FooPointer { // Compliant, std::unique_ptr is use to handle memory managementunique_ptr<Foo> pFoo;
public:FooPointer(int initValue) : pFoo(std::make_unique<Foo>(initValue) {}
};

A polymorphic base class can look like this:

class Base { // Compliant, the virtual destructor is defaulted
public:virtual ~Base() = default;Base(Base const &) = delete;Base &operator=(Base const &) = delete;
};

Exceptions

  • Empty destructors are treated as though they were defaulted.
  • There are several cases when this rule should not be followed. For instance, if your class is manually handling a resource, logging when being constructed/copied, maintaining some kind of counter, having non-transient data that should not be copied (like capacity for std::vector)…​ In that case, it should still follow the rule of 5 (S3624). And you should consider if you can isolate this specific behavior in a base class or a dedicated member data, which would allow you to still follow the rule of 0.

See

  • S3624
  • S1235

 


http://www.mrgr.cn/news/92855.html

相关文章:

  • Hadoop之01:HDFS分布式文件系统
  • I2C驱动(十一) -- gpio模拟的i2c总线驱动i2c-gpio.c分析
  • 第一个Vue项目笔记(待更新)
  • 250301-OpenWebUI配置DeepSeek-火山方舟+硅基流动+联网搜索+推理显示
  • C语言学习笔记-初阶(19)猜数字游戏:分支、循环结构的应用
  • 大数据学习(51)-MySQL数据库学习
  • IP-----双重发布
  • ConcurrentHashMap
  • 初始化列表
  • 详解:事务注解 @Transactional
  • 安装 Open WebUI
  • 【HarmonyOS NEXT】控制 WebP 格式动图播放次数的实现方案
  • Redis---缓存穿透,雪崩,击穿
  • MySQL慢查询分析与处理
  • C++:类和对象(下篇)
  • 实验环境搭建集锦(docker linux ros2+强化学习环境+linux上单片机串口调试)
  • nuxt常用组件库html-validator、@nuxtjs/i18n、@nuxt/image、@unocss/nuxt使用解析
  • dj算法与分层图最短路径
  • LeetCode 解题思路 6(Hot 100)
  • 机器学习:线性回归,梯度下降,多元线性回归