当前位置: 首页 > 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 complex
  Foo* 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 management
  unique_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

 

相关文章:

  • 【Envi遥感图像处理】014:影像非监督分类
  • JS宏案例:多项式回归
  • 数据集笔记:新加坡 地铁(MRT)和轻轨(LRT)票价
  • Spark核心之01:架构部署、sparkshell、程序模板
  • 前端面试题最新版
  • DeepSeek + dify 搭建本地知识库
  • DifyでOracle Base Database Service(23ai)を利用する設定手順
  • 1114棋盘问题acwing(深度优先搜索)
  • 机器学习的三个基本要素
  • Docker入门指南:Windows下docker配置镜像源加速下载
  • 火山引擎AI一体机-DeepSeek版来了
  • 代码随想录算法【Day60】
  • 数据结构(初阶)(七)----树和二叉树(前中后序遍历)
  • 【2025-03-02】基础算法:二叉树 相同 对称 平衡 右视图
  • 前端控制器模式
  • QT-对象树
  • partner‘127.0.0.1:3200‘ not reached
  • JAVA SE 包装类和泛型
  • ​​“百镜大战”引爆AI眼镜元年:端侧大模型+轻量化设计,2025销量或暴增230%! ​
  • 开源模型应用落地-工具使用篇-Spring AI(七)
  • 班组建设展板哪个网站有/电商运营工资大概多少
  • 17zwd一起做网站教学视频/企业推广
  • 海外做淘宝网站/刚开的店铺怎么做推广
  • 预付网站制作费怎么做凭证/辽宁网站seo
  • 怎样用微信做购物网站/windows优化大师官方下载
  • .org做商业网站/免费访问国外网站的app