You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++自定义类实现时是否需要遵循Rule of Five(五法则)?

C++特殊成员函数定义最佳实践

问题背景

C++语言规则中对特殊成员函数的隐式生成有明确约束:

如果类中存在用户自定义(或通过= default、= delete声明)的析构函数、拷贝构造函数、拷贝赋值运算符,会阻止编译器隐式定义移动构造函数与移动赋值运算符,因此任何需要支持移动语义的类,都必须声明全部五个特殊成员函数。

提问者给出的测试代码如下:

#include <string>
#include <iostream>

class Data {
private:
    std::string m_name;

public:
    Data() { m_name = "stackman"; }
    ~Data() = default;
    Data(const Data&) = delete;
    Data& operator=(const Data&) = delete;
    Data(Data&&) = delete;
    Data& operator=(Data&&) = delete;

    std::string get_name() { return m_name; }
};

int main()
{
    Data person;

    std::cout << person.get_name() << std::endl;

}

提问者发现不同资料存在矛盾描述:有说法称如果析构函数设置为=default,且不需要其他构造、赋值函数,就无需对其进行delete或显式定义,需要明确该场景下的标准最佳实践。


规则说明与实践方案

首先要澄清一个常见误区:用=default声明的析构函数属于用户声明的析构函数,和手写实现的析构函数完全等价,一样会触发编译器隐式移动操作的抑制逻辑,不存在“写=default就不影响其他特殊成员函数生成”的特殊规则。

针对不同需求场景,对应最佳实践如下:

  • 场景1:类仅需要在固定作用域内创建使用,禁止拷贝、移动
    给出的示例代码可以正常运行,但属于冗余写法。示例中类成员只有std::string,编译器隐式生成的析构函数完全可以正确完成资源释放,不需要手动写~Data() = default;。同时,只要显式delete拷贝构造函数和拷贝赋值运算符,编译器就不会生成默认拷贝操作,也不会隐式生成移动操作,不需要额外手动delete移动构造和移动赋值。
    该场景下最简正确实现的特殊成员函数部分只需要保留:
    Data() { m_name = "stackman"; }
    Data(const Data&) = delete;
    Data& operator=(const Data&) = delete;
    
  • 场景2:类需要支持移动语义
    只要显式声明了析构、拷贝构造、拷贝赋值运算符中的任意一个,就必须显式声明移动构造和移动赋值运算符,要么用=default让编译器生成默认实现,要么编写自定义逻辑,严格遵循五法则要求,避免移动语义被意外抑制。
  • 场景3:类不需要自定义资源释放逻辑,所有成员都可以用编译器默认逻辑处理
    不需要手动声明任何特殊成员函数,编译器会按规则隐式生成默认构造、析构、拷贝、移动全套操作。不要额外添加=default声明的析构函数,避免画蛇添足导致移动语义被意外抑制。

内容的提问来源于stack exchange,提问作者lvalue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 18:48:20