zoukankan      html  css  js  c++  java
  • C++11 =default 和 =delete

    在C++中,声明自定义的类型之后,编译器会默认生成一些成员函数,这些函数被称为默认函数。其中包括

    (1)(默认)构造函数

    (2)拷贝(复制)构造函数

    (3)拷贝(复制)赋值运算符

    (4)移动构造函数

    (5)移动赋值运算符

    (6)析构函数

    另外,编译器还会默认生成一些操作符函数,包括

    (7)operator ,

    (8)operator &

    (9)operator &&

    (10)operator *

    (11)operator ->

    (12)operator ->*

    (13)operator new

    (14)operator delete

    【1】显式缺省函数(=default)

    如果类设计者又实现了这些函数的自定义版本后,编译器就不会去生成默认版本。

    大多数时候,我们需要声明带参数的构造函数,此时就不会生成默认构造函数,这样会导致类不再是POD类型(可参见随笔《C++11 POD类型》),从而影响类的优化:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Test 
     5 {
     6 public:
     7     Test(int i) : data(i) {}
     8 
     9 private:
    10     int data;
    11 };
    12 
    13 int main()
    14 {
    15     std::cout << std::is_pod<Test>::value << std::endl;  // 0
    16 }

    C++11中提供了新的机制来控制默认函数生成来避免这个问题:声明时在函数末尾加上”= default”来显式地指示编译器去生成该函数的默认版本,这样就保证了类还是POD类型:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Test 
     5 {
     6 public:
     7     Test() = default;  // 显式指定缺省函数
     8     Test(int i) : data(i) {}
     9 
    10 private:
    11     int data;
    12 };
    13 
    14 int main()
    15 {
    16     std::cout << std::is_pod<Test>::value << std::endl;  // 1
    17 }

    【2】显式删除函数(=delete)

    另一方面,有时候可能需要限制一些默认函数的生成。

    例如:需要禁止拷贝构造函数的使用。以前通过把拷贝构造函数声明为private访问权限,这样一旦使用编译器就会报错。

    而在C++11中,只要在函数的定义或者声明后面加上”= delete”就能实现这样的效果(相比较,这种方式不容易犯错,且更容易理解):

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Test 
     5 {
     6 public:
     7     Test() = default;  // 显式指定缺省函数
     8     Test(int i) : data(i) {}
     9     Test(const Test& t) = delete; // 显式删除拷贝构造函数
    10 
    11 private:
    12     int data;
    13 };
    14 
    15 int main()
    16 {
    17     Test objT1;
    18 //    Test objT2(objT1); // 无法通过编译
    19 }

    【3】其他应用

    (1)= default和= delete 能够更加精准的控制类的默认函数版本。其中,= default同样也能在类外的定义中修饰成员函数:

     1 class Example 
     2 {
     3 public:
     4     Example() = default;
     5     Example(const Example&);
     6 
     7 private:
     8     int data;
     9 };
    10 
    11 Example::Example(const Example& ex) = default;

    这样的好处是,能够为一个类实现多个版本,只要我们在头文件里声明同样的函数,而在不同的cpp文件中用不同的方法实现,当选择不同的cpp编译时产生的版本就不同。

    (2)关于= delete,它不仅局限于限制生成默认函数,还能避免编译器做一些不必要的隐式数据转换:

    隐式转换示例:

     1 class Example 
     2 {
     3 public:
     4     Example(int i) {}
     5 };
     6 
     7 
     8 int main()
     9 {
    10     Example ex(1);
    11     Example ex1('a');  // 编译成功,char会隐式装换成int型
    12 }

    有时候我们不想要这种隐式转换:

     1 class Example 
     2 {
     3 public:
     4     Example(int i) {}
     5     Example(char c) = delete;
     6 };
     7 
     8 
     9 int main()
    10 {
    11     Example ex(1);
    12//   Example ex1('a');  // 无法通过编译
    13 }

    这个方法也能用于普通函数:

    1 void func(int i) {}
    2 void func(char c) = delete;
    3 
    4 int main()
    5 {
    6     func(1);
    7//   func('a');   // 编译失败
    8 }

    另外,还有很多使用场景,例如,显式删除new操作符来避免在堆上分配对象、显式删除析构函数用于构建单例模式等等。

    总之,default只能用于6个特殊成员函数,但delete可用于任何成员函数。

    good good study, day day up.

    顺序 选择 循环 总结

  • 相关阅读:
    Winget
    全部所学知识
    重装系统
    srs更改端口号导致webrtc播放异常
    .NET性能优化方面的总结(转)
    从自动变换页面背景CSS改写成变换背景图
    网页级在线性能网站测试介绍
    ASP.NET服务器端控件学习(一)
    Nginx源码分析内存池
    使用Memcached提高.NET应用程序的性能
  • 原文地址:https://www.cnblogs.com/Braveliu/p/12247471.html
Copyright © 2011-2022 走看看