C++11新特性 =default 与 =delete,看完你就会懂,会用了

简述 =default和=delete

C++11加入了=default与=delete两个关键字,它们只作用于big five(默认构造、拷贝构造、赋值构造、析构函数和带&&的赋值与拷贝构造)不带&&的前面一些叫big three。单纯从英文翻译为中文来说,default是默认的意思,delete是删除的意思。在这里也是大概这样的意思。=default是保留默认的big five,=delete是删除默认的big five。

写空的类不是空的

什么时候空的类不再是空的呢,当C++编译器处理过它之后。是这样的,如果你自己没声明什么,编译器就会为它声明一个拷贝构造、一个无参构造(默认构造)、赋值构造和析构函数(也就是big three)。如果你没有声明任何构造函数,编译器也会为你声明一个默认构造。所有这样函数都是public且inline(内联)。

下面代码说明:

#include <iostream>

using namespace std;

class Empty{};



int main()
{
    Empty e1;
    Empty e2(e1);
    e2 = e1;
}

我编译过了并且可以运行,说明了编译器给我们搞了big three (侯捷是这样称呼的)。类似这样的操作:这都是编译器默认产生的。我们可以用=delete 这个关键字拒绝给我们产生这些。

编译器为我们生成的big three

class Empty
{
  public:
    Empty(){...}
    Empty(const Empty& rhs){...}
    ~Empty(){...}
    
    Empty& operator = (const Empty& rhs){...}
};

编译器为什么为我们创建big three呢?
这些函数做了什么呢?默认构造和构造函数主要是给编译器一个地方用来放置藏身幕后的代码,像是唤起基类或叫父类非静态成员的构造函数与析构函数,编译器生产出来的析构函数是非虚函数,除非这个类的基类本身有虚析构函数。至于拷贝构造和赋值构造,编译器合成版只是单纯将源对象的每一个非静态数据成员拷贝到目的对象。

=defult =delete 一起谈谈

如果你自行定义了一个构造函数,那么编译器就不会再给你一个默认构造函数。如果你强制加上 = default,就可以重新获得并使用默认构造函数。
=delete告诉编译器不要定义它。必须出现在声明式。适用于任何成员函数。也适用于构造函数,但后果自负。

例子1:

class Zoo
{
public:
    Zoo(int i1, int i2):d1(i1),d2(i2){}
    Zoo(const Zoo&) = delete;  //保留默认构造函数
    Zoo(ZOO&&) = default; //保留右值引用,不懂可以先放一放,以后文章谈
    Zoo& operator = (const Zoo&) = default;//保留默认的赋值操作
    Zoo& operator =(const Zoo&&) = delete;//删除右值引用的赋值操作
    virtual ~Zoo(){}
private:
    int d1, d2;
}

例子2:

#include <iostream>

using namespace std;

class Foo
{
public:
    Foo(int i):m_i(i){}
    Foo() = default; //与上一个构造函数可以并存
    Foo(const Foo& x):m_i(x.m_i){}

    //!Foo(const Foo&) = default; error: ‘Foo::Foo(const Foo&)’ cannot be overloaded with ‘Foo::Foo(const Foo&)’
    //!Foo(const Foo &) = delete; error同上

    Foo& operator = (const Foo& x)
    {
        m_i = x.m_i;
        return *this;
    }
   //! Foo& operator = (const Foo& x) = default; error同上
    //!Foo& operator = (const Foo& x) = delete; error同上

    //!void func1() = default; error:'Void Foo:: func1()'cannot be defaulted
    void func2() = delete;

   //! ~Foo() = delete; //删除了析构函数,error:use of deleted function'Foo::~Foo()'
    ~Foo() = default;
private:
    int m_i;
};


int main()
{
   Foo f1(5);
   Foo f2;
   Foo f3(f1);
   f3 = f2;
}

编译的结果:
在这里插入图片描述
注意:
=default;用于big five 之外是何意义?无意义,编译报错。

=delete;可用于任何函数身上。(=0只用于virtual函数(虚函数))。

一些奇怪的类

没有拷贝函数的类,这是一个简单的设计模式–单例

class NoCopy
{
public:
    NoCopy() = default; //保留默认构造函数
    NoCopy(const NoCopy&) = delete; //删除拷贝函数
    NoCopy &operator = (const NoCopy&) = delete;//删除拷贝赋值函数
    ~NoCopy() = default;//保留默认的析构函数
};

没有析构函数的类,释放不了资源了

#include <iostream>

using namespace std;

class NoDtor
{
public:
  NoDto() = default;   //保留默认的构造函数
 ~NoDto() = delete;    //删除了析构函数
};

int main()
{
    NoDtor nd; //error:析构函数已经被删除了
    NoDtor *p = new NoDtor();
    delete p; //error:析构函数已经被删除了
}

只有友元和成员才可以复制的类

class PrivateCopy
{
private:
    PrivateCopy(const PrivateCopy&){} //拷贝构造私有了
    PrivateCopy &operator = (const PrivateCopy&){}//赋值函数私有了
public:
    PrivateCopy() = default; //保留默认的构造函数
    ~PrivateCopy();
};

这个类不允许普通的代码去复制,但仍然可以被friends(友元)和成员赋值。想要做到完全禁止复制,要想第一个例子一样做。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

困了就喝白茶

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值