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

C++ 中的 delete 与 default 关键字详解

在 C++ 中,delete 和 default 是两个用于控制类特殊成员函数行为的关键字,它们在现代 C++ 编程中扮演着重要角色。下面我将详细解释这两个关键字的用法、区别以及实际应用场景。

一、delete 关键字

1. 基本作用

delete 用于显式禁止某些函数的使用(包括任何形式的调用)

2. 主要应用场景

禁止拷贝操作
class NonCopyable {
public:NonCopyable() = default;// 禁止拷贝构造函数NonCopyable(const NonCopyable&) = delete;// 禁止拷贝赋值运算符NonCopyable& operator=(const NonCopyable&) = delete;
};int main() {NonCopyable a;// NonCopyable b = a;  // 错误:拷贝构造函数被删除// a = NonCopyable();  // 错误:拷贝赋值运算符被删除
}
禁止特定参数类型的函数
class Logger {
public:void log(int value) { /* ... */ }void log(double) = delete;  // 禁止使用 double 参数调用
};int main() {Logger log;log.log(42);    // OK// log.log(3.14); // 错误:log(double) 被删除
}
禁止不希望的隐式转换
class MyInt {int value;
public:MyInt(int v) : value(v) {}  // 允许 int 构造MyInt(char) = delete;       // 禁止 char 构造
};int main() {MyInt a(10);    // OK// MyInt b('x'); // 错误:构造函数被删除
}

3. 重要特性

  • 比 C++03 的 private 未实现方法更安全(编译时错误 vs 链接时错误)

  • 可应用于任何函数(成员函数、非成员函数、运算符)

  • 必须在函数第一次声明时删除

  • 支持模板特化删除

二、default 关键字

1. 基本作用

default 用于显式请求编译器生成函数的默认实现

2. 主要应用场景

恢复默认构造函数
class Widget {
public:// 自定义构造函数会抑制默认构造函数Widget(int value) { /* ... */ }// 显式恢复默认构造函数Widget() = default;
};int main() {Widget w1(10);  // 使用自定义构造函数Widget w2;      // 使用默认构造函数
}
显式声明特殊成员函数

3. 重要特性

  • 只能用于有默认实现的特殊成员函数:

    • 默认构造函数

    • 析构函数

    • 拷贝构造函数

    • 拷贝赋值运算符

    • 移动构造函数 (C++11)

    • 移动赋值运算符 (C++11)

  • 生成的内联性与隐式生成相同

  • 可在类内定义(隐式内联)或类外定义

三、对比总结表

特性deletedefault
目的禁止函数使用显式生成默认实现
适用函数任何函数特殊成员函数
主要用途1. 禁止拷贝/移动
2. 禁止特定重载
3. 禁止隐式转换
1. 恢复默认构造函数
2. 显式声明特殊成员
3. 保持平凡类型特性
编译检查编译时报错编译时生成代码
对类的影响使类不可拷贝/不可调用保持类的平凡性(trivial)
C++版本C++11 引入C++11 引入

四、联合使用示例

class Advanced {
public:// 显式生成默认构造函数Advanced() = default;// 禁止拷贝Advanced(const Advanced&) = delete;Advanced& operator=(const Advanced&) = delete;// 允许移动Advanced(Advanced&&) = default;Advanced& operator=(Advanced&&) = default;// 禁止特定参数类型的调用void process(int) {}void process(double) = delete;
};int main() {Advanced a;Advanced b(std::move(a)); // OK:使用移动构造// Advanced c(a);         // 错误:拷贝构造被删除a.process(10);           // OK// a.process(3.14);       // 错误:double版本被删除
}

五、最佳实践指南

1. delete 使用建议

  • 优先于私有声明:使用 =delete 替代传统的私有未实现方法

  • 禁用拷贝时同时禁用赋值:保持一致性

  • 用于接口净化:禁止不希望的参数类型转换

  • 配合类型系统:创建更安全的API

// 防止在堆上分配对象
class StackOnly {
public:void* operator new(size_t) = delete;void operator delete(void*) = delete;
};

2. default 使用建议

  • 明确设计意图:显式声明而非依赖隐式生成

  • 恢复默认构造函数:当存在其他构造函数时

  • 保持平凡性:当需要平凡可复制类型时

  • 移动操作:需要时显式声明(否则可能抑制生成)

// 保持平凡可复制特性
struct TrivialType {int x;double y;TrivialType() = default;TrivialType(const TrivialType&) = default;TrivialType& operator=(const TrivialType&) = default;~TrivialType() = default;
};

3. 现代 C++ 类设计模式

五法则模式 (Rule of Five)
class ResourceHandler {int* resource;
public:// 构造函数explicit ResourceHandler(size_t size) : resource(new int[size]) {}// 1. 析构函数~ResourceHandler() { delete[] resource; }// 2. 拷贝构造函数ResourceHandler(const ResourceHandler& other) : resource(new int[/*size*/]) {std::copy(/*...*/);}// 3. 拷贝赋值运算符ResourceHandler& operator=(const ResourceHandler& rhs) {if (this != &rhs) {// 拷贝实现}return *this;}// 4. 移动构造函数ResourceHandler(ResourceHandler&& other) noexcept : resource(std::exchange(other.resource, nullptr)) {}// 5. 移动赋值运算符ResourceHandler& operator=(ResourceHandler&& rhs) noexcept {if (this != &rhs) {delete[] resource;resource = std::exchange(rhs.resource, nullptr);}return *this;}
};
零法则模式 (Rule of Zero)
// 使用智能指针和标准库组件,无需自定义特殊成员
class RuleOfZero {std::unique_ptr<int[]> data;  // 自动处理资源std::vector<double> items;    // 自动管理内存
public:RuleOfZero(size_t size) : data(std::make_unique<int[]>(size)) {}// 不需要声明任何特殊成员函数// 编译器会自动生成正确的拷贝/移动操作或删除它们
};

六、注意事项与常见错误

1. default 的限制

  • 不能用于普通成员函数

  • 不能改变函数的默认行为

  • 类外定义时不能添加 inline 等修饰符

class Example {
public:// 错误:不能 default 普通函数void normalFunction() = default;
};

2. delete 的特殊用法

  • 可删除 new 运算符防止堆分配

  • 可删除析构函数防止栈分配(需配合 new)

    // 只能在堆上创建的对象
    class HeapOnly {
    public:void destroy() { delete this; }
    private:~HeapOnly() = default;  // 私有析构
    };// 只能在栈上创建的对象
    class StackOnly {
    public:void* operator new(size_t) = delete;
    };

    3. 继承关系中的影响

  • 基类的删除函数会被派生类继承

  • 虚函数可以删除,但需注意多态调用风险

    class Base {
    public:virtual void func() = delete;
    };class Derived : public Base {
    public:void func() override {}  // 错误:尝试覆盖已删除函数
    };

    七、C++20/23 增强

    1. 显式对象参数 (C++23)

    struct S {void f(this S&);  // 显式对象参数void f(this S&&) = delete;  // 禁止右值调用
    };

    2. =delete 支持自定义消息 (提案)

    // 未来可能支持
    void deprecated() = delete("Use new_function instead");

    总结

    delete 和 default 是现代 C++ 中管理类特殊成员函数的核心机制:

  • delete 提供更强的接口约束能力

  • default 提供更清晰的默认行为控制

  • 关键实践原则:

  • 优先使用 Rule of Zero,让编译器自动处理资源

  • 需要特殊处理时使用 Rule of Five

  • 使用 delete 明确禁止不希望的接口

  • 使用 default 明确依赖编译器默认行为

  • 在类定义中显式声明特殊成员函数的意图

http://www.dtcms.com/a/337532.html

相关文章:

  • diffusion model(1.4) 相关论文阅读清单
  • 遥感数字图像处理教程——第三章课后习题
  • flutter项目适配鸿蒙
  • 人工智能 | 基于大数据的皮肤病症状数据可视化分析系统(matlab源码)
  • Java设计模式-桥接模式
  • Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
  • API 接口在电商中的重要应用​||关于API接口接入
  • 构建者设计模式 Builder
  • python学习DAY45打卡
  • 【运维实战】系统全链路监测方案~架构到实践
  • 【HTML】document api
  • 【每天学点‘音视频’】前向纠错 和 漏包重传
  • 图像分类精度评价的方法——误差矩阵、总体精度、用户精度、生产者精度、Kappa 系数
  • 在 PyCharm Notebook 中安装 YOLO
  • Google 的 Opal:重新定义自动化的 AI 平台
  • 【项目】分布式Json-RPC框架 - 项目介绍与前置知识准备
  • ARM架构下的cache transient allocation hint以及SMMUv2的TRANSIENTCFG配置详解
  • kafka 冲突解决 kafka安装
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘pygame’问题
  • 数据赋能(401)——大数据——持续学习与优化原则
  • 删除并获得点数
  • 线程间通信(互斥锁,死锁,信号量)
  • 148-基于Python的2024物流年度销售收入数据可视化分析系统
  • PYTHON让繁琐的工作自动化-函数
  • 功能测试相关问题
  • 使用空模型实例调用辅助函数,确定在量化过程中哪些层会被跳过(43)
  • 实现make/makefile
  • Android RxBinding 使用指南:响应式UI编程利器
  • AI智能的“进化史”:从弱人工智能到通用人工智能的跨越
  • Linux中基于Centos7使用lamp架构搭建个人论坛(wordpress)