学完Efficient c++ (05)

27 篇文章 0 订阅
24 篇文章 0 订阅

构造和析构一方面是对象的诞生和终结;另一方面,它们也意味着资源的开辟和归还。

条款05:了解C++默默编写并调用了哪些函数

编译器会主动为你编写的任何类声明一个拷贝构造函数、拷贝复制操作符和一个析构函数,同时如果你没有声明任何构造函数,编译器也会为你声明一个default版本的拷贝构造函数,这些函数都是publicinline的。注意,上边说的是声明,只有当这些函数有调用需求的时候,编译器才会帮你去实现它们。

C++ 中的空类并不是真正意义上的空类,编译器会为它预留以下内容:

class Empty {
public:
    Empty() { ... }                           // 默认构造函数(没有任何构造函数时)
    Empty(const Empty&) { ... }               // 拷贝构造函数
    Empty(Empty&&) { ... }                    // 移动构造函数 (since C++11)
    ~Empty() { ... }                          // 析构函数(non-virtual)
    
    Empty& operator=(const Empty&) { ... }    // 拷贝赋值运算符
    Empty& operator=(Empty&&) { ... }         // 移动赋值运算符 (since C++11)
};

唯有当这些函数被调用时,它们才会真正被编译器创建出来,下面代码将造成上述每一个函数被创建:

mpty e1;                   // 默认构造函数 & 析构函数
Empty e2(e1);               // 拷贝构造函数
Empty e3 = std::move(e2);   // 移动构造函数 (since C++11)
e2 = e1;                    // 拷贝赋值运算符
e3 = std::move(e1);         // 移动赋值运算符 (since C++11)

需要注意的是,拷贝赋值运算符只有在允许存在时才会自动创建,比如以下情况:

class NamedObject {
private:
    std::string& nameValue;
};

在该类中,我们有一个string引用类型,然而引用无法指向不同对象,因此编译器会拒绝为该类创建一个默认的拷贝赋值运算符。

除此之外,以下情形也会导致拷贝赋值运算符不会自动创建:

  1. 类中含有const成员。
  2. 基类中含有private的拷贝赋值运算符。

注:编译器替你实现的函数可能在类内引用、类内指针、有const成员以及类型有虚属性的情形下会出问题。

  • 对于拷贝构造函数,你要考虑到类内成员有没有深拷贝的需求,如果有的话就需要自己编写拷贝构造函数/操作符,而不是把这件事情交给编译器来做。
  • 对于拷贝构造函数,如果类内有引用成员或const成员,你需要自己定义拷贝行为,因为编译器替你实现的拷贝行为在上述两个场景很有可能是有问题的。
  • 对于析构函数,如果该类有多态需求,请主动将析构函数声明为virtual,具体请看条款07 。

除了这些特殊的场景以外,如果不是极其简单的类型,请自己编写构造、析构、拷贝构造和赋值操作符、移动构造和赋值操作符(C++11、如有必要)这六个函数。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值