C++中的 =default和=delete

本文深入探讨了C++11中引入的默认函数和删除函数特性。介绍了如何使用'default'关键字为特殊成员函数生成默认实现,以及使用'delete'关键字禁用不需要的函数,提高代码效率和安全性。

首先,什么是默认功能呢(Defaulted Function)
明确默认的函数声明式一种新的函数声明方式,在C++11发布时做出了更新。C++11允许添加“=default”说明符到函数声明的末尾,以将该函数声明为显示默认构造函数。这就使得编译器为显示默认函数生成了默认实现,它比手动编程函数更加有效。

例如,每当我们声明一个有参构造函数时,编译器就不会创建默认构造函数。在这种情况下,我们可以使用default说明符来创建默认说明符。以下代码演示了如何创建:

// use of defaulted functions
#include <iostream>
using namespace std;

class A {
public:
    // A user-defined
    A(int x){
        cout << "This is a parameterized constructor";
    }

    // Using the default specifier to instruct
    // the compiler to create the default implementation of the constructor.
    A() = default;
};

int main(){
    A a;          //call A()
    A x(1);       //call A(int x)
    cout<<endl;
    return 0;
} 

在这里插入图片描述
在上面的例子中,我们不必指定构造函数A()的主体,因为通过附加说明符’= default’,编译器将创建此函数的默认实现。

那么使用此“=default”符号有什么限制?

  • 默认函数需要用于特殊的成员函数(默认构造函数,复制构造函数,析构函数等),或者没有默认参数。例如,以下代码解释了非特殊成员函数不能默认:
// non-special member functions can't be defaulted(非特殊成员函数不能使用default) 
class B { 
public: 
    // Error, func is not a special member function. 
    int func() = default;  
      
    // Error, constructor B(int, int) is not a special member function. 
    B(int, int) = default;  
  
    // Error, constructor B(int=0) has a default argument. 
    B(int = 0) = default;  
}; 
int main() { 
    return 0; 
} 

运行结果:
在这里插入图片描述
当我们可以使用“{}”简单的空的实体时,使用’= default’有什么优点?

尽管两者可能表现相同,但使用default而不是使用{}仍然有一定的好处。以下几点做了一定的解释:

  1. 给用户定义的构造函数,即使它什么也不做,使得类型不是聚合,也不是微不足道的。如果您希望您的类是聚合类型或普通类型(或通过传递性,POD类型),那么需要使用’= default’。
  2. 使用’= default’也可以与复制构造函数和析构函数一起使用。例如,空拷贝构造函数与默认拷贝构造函数(将执行其成员的复制副本)不同。对每个特殊成员函数统一使用’= default’语法使代码更容易阅读。

再来说一下Deleted Function

在C ++ 11之前,操作符delete 只有一个目的,即释放已动态分配的内存。而C ++ 11标准引入了此操作符的另一种用法,即:禁用成员函数的使用。这是通过附加= delete来完成的; 说明符到该函数声明的结尾。

使用’= delete’说明符禁用其使用的任何成员函数称为expicitly deleted函数。

虽然不限于它们,但这通常是针对隐式函数。以下示例展示了此功能派上用场的一些任务:

禁用拷贝构造函数:

// copy-constructor using delete operator 
#include <iostream> 
using namespace std; 
  
class A { 
public: 
    A(int x): m(x) { } 
      
    // Delete the copy constructor 
    A(const A&) = delete;      
    // Delete the copy assignment operator 
    A& operator=(const A&) = delete;  
    int m; 
}; 
  
int main() { 
    A a1(1), a2(2), a3(3); 
    // Error, the usage of the copy assignment operator is disabled 
    a1 = a2;   
    // Error, the usage of the copy constructor is disabled 
    a3 = A(a2);  
    return 0; 
} 

禁用不需要的参数转换

// type conversion using delete operator 
#include <iostream> 
using namespace std; 
class A { 
public: 
    A(int) {} 

    // Declare the conversion constructor as a  deleted function. Without this step,  
    // even though A(double) isn't defined,  the A(int) would accept any double value
    //  for it's argumentand convert it to an int 
    A(double) = delete;  
}; 
int main() { 
    A A1(1); 
    // Error, conversion from  double to class A is disabled. 
    A A2(100.1);  
    return 0; 
} 

请注意,删除的函数是隐式内联的,这一点非常重要。删除的函数定义必须是函数的第一个声明。换句话说,以下方法是将函数声明为已删除的正确方法:

class C {
public:
         C(C& a) = delete;
};

但是以下尝试声明删除函数的方法会产生错误:

// incorrect syntax of declaring a member function as deleted 
class C  { 
public: 
    C(); 
}; 
  
// Error, the deleted definition of function C must be the first declaration of the function. 
C::C() = delete;  

最后,明确删除函数有什么好处?
删除特殊成员函数提供了一种更简洁的方法来防止编译器生成我们不想要的特殊成员函数。(如“禁用拷贝构造函数”示例中所示)。
删除正常成员函数或非成员函数可防止有问题的类型导致调用非预期函数(如“禁用不需要的参数转换”示例中所示)。

<think>好的,我需要回答用户关于C++=default=delete的用法及区别的问题。首先,我应该回顾一下这两个关键字的基本概念。根据用户提供的引用,=default用于显式要求编译器生成默认的函数实现,而=delete则是禁止编译器生成特定函数,或者禁用非成员函数,防止不期望的类型转换或调用。 接下来,我需要整理它们的应用场景。比如,当用户自定义了有参构造函数后,编译器不再生成默认构造函数,这时可以使用=default来恢复默认构造函数的生成。而对于=delete,常见的情况是禁用拷贝构造函数或拷贝赋值运算符,以防止对象被拷贝,这在管理资源时尤为重要,比如智能指针的实现。 然后,我需要区分两者的使用范围。根据引用[4],=delete可以用于任何函数,包括普通成员函数非成员函数,而=default仅适用于编译器能够自动生成的默认特殊成员函数,如构造函数、析构函数、拷贝控制成员等。例如,用户可能希望禁止某个函数接受某些参数类型,这时可以使用=delete来删除特定的重载版本,避免隐式转换带来的问题。 还需要提到使用这两个关键字的好处。比如,使用=default可以保持代码的简洁,同时明确表达意图,而=delete则增强了代码的安全性,防止误用某些函数。引用[1]中提到,删除正常成员函数或非成员函数可以防止有问题的类型导致调用非预期的函数,比如禁用不需要的参数转换。 此外,需要结合具体的代码示例来说明两者的用法。比如引用[1]中的例子,类A定义了有参构造函数后,使用A() = default来生成默认构造函数。而如果希望禁用拷贝构造函数,可以声明其为=delete,这样编译器不会生成默认的拷贝构造,任何尝试拷贝该类的对象都会导致编译错误。 最后,我应该总结两者的主要区别,包括用途、适用范围语法要求。确保用户能够清晰理解何时使用=default,何时使用=delete,以及它们如何帮助编写更安全、更高效的C++代码。</think>### C++中`=default`与`=delete`的用法及区别 #### 一、`=default`的用途 1. **显式生成默认函数** 当类中已定义其他构造函数(如带参构造函数),但需要保留默认构造函数时,可通过`=default`显式要求编译器生成默认实现。例如: ```cpp class A { public: A(int x) {} // 用户定义构造函数 A() = default; // 显式生成默认构造函数 }; ``` 此操作确保`A a;`能调用默认构造函数[^1]。 2. **适用于特殊成员函数** `=default`仅可用于编译器默认生成的函数,包括: - 默认构造函数 - 拷贝/移动构造函数 - 拷贝/移动赋值运算符 - 析构函数 示例: ```cpp class MyClass { public: MyClass() = default; // 默认构造函数 MyClass(const MyClass&) = default; // 拷贝构造函数 MyClass& operator=(const MyClass&) = default; // 拷贝赋值运算符 }; ``` 通过`=default`,可保持特殊成员函数的默认行为,同时允许其他自定义操作[^2]。 --- #### 二、`=delete`的用途 1. **禁用特殊成员函数** 用于阻止编译器生成默认实现,常见于禁用拷贝或移动操作。例如: ```cpp class NonCopyable { public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; // 禁用拷贝构造 NonCopyable& operator=(const NonCopyable&) = delete; // 禁用拷贝赋值 }; ``` 此时尝试拷贝`NonCopyable`对象会引发编译错误,避免资源重复释放等问题[^3]。 2. **禁止特定函数调用** `=delete`还可用于普通成员函数或非成员函数,防止隐式类型转换或参数匹配问题。例如: ```cpp void process(int x) {} void process(double) = delete; // 禁止使用double参数调用 process(10); // 允许 process(3.14); // 编译错误 ``` 此用法可避免因类型转换导致的逻辑错误[^1]。 --- #### 三、关键区别总结 | **特性** | **`=default`** | **`=delete`** | |----------------|-----------------------------------------|-----------------------------------------| | **用途** | 显式生成默认函数实现 | 禁用函数生成或调用 | | **适用范围** | 仅限编译器可生成的默认特殊成员函数 | 任意函数(包括普通成员函数、非成员函数) | | **语法要求** | 需在函数声明末尾添加 | 可在函数声明或定义中使用 | | **典型场景** | 保留默认构造函数或拷贝控制语义 | 禁用拷贝、限制参数类型或特定重载 | --- #### 四、应用示例 1. **`=default`恢复默认行为** 当类需要同时支持自定义构造默认构造时: ```cpp class B { public: B(int value) : data(value) {} B() = default; // 显式生成默认构造函数 private: int data = 0; }; ``` 2. **`=delete`防止隐式转换** 禁用不需要的构造函数重载: ```cpp class String { public: String(const char* str) {} String(char) = delete; // 禁止通过char类型构造 }; String s1("hello"); // 允许 String s2('a'); // 编译错误 ``` --- #### 五、优点总结 - **`=default`**:保持代码简洁,明确依赖编译器生成的默认逻辑,避免手动实现冗余代码[^4]。 - **`=delete`**:增强类型安全性,防止不合理的操作或参数转换,提升代码健壮性[^1]。 相关问题
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一倾而尽

你的鼓励将是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值