《Effective C++》Item5:了解C++默默编写并调用了哪些函数

如果一个C++类没有声明自己的构造函数、拷贝构造函数、拷贝赋值运算符和析构函数的话,那么编译器就会为我们生成一个。所有这些由编译器为我们生成的函数都是publicinline的。这些函数只有当被调用到的时候,才会被创建出来。

但是这些函数都做了什么呢?主要是处理一些程序幕后的工作,即:编译器向这些函数中安插了额外的代码来处理一些常规事务,例如:调用父类的构造函数和析构函数、初始化虚函数表指针等。

至于拷贝构造函数和拷贝赋值运算符,编译器只是简单地将对象中的成员变量进行浅拷贝

例如下面的这个类:

template<typename T>
class NamedObject
{
public:
    NamedObject(const char *name, const T &value);

private:
    std::string _name;
    T _objectValue;
};

//...

int main()
{
    NamedObject<int> namedObject;
    return 0;
}

在这个类中,由于类NamedObject没有定义拷贝构造函数和拷贝赋值运算符,因此编译器将生成它们:分别针对对象的两个成员变量:_name_objectValue进行浅拷贝。

其中,_name是一个std::string对象,它存在一个拷贝构造函数,因此编译器将直接使用它;此时参数类型T被实例化为了int。因此,编译器也将直接拷贝这个整型成员变量的每个字节。

但是,编译器也可能会拒绝为类生成拷贝构造函数和拷贝辅助运算符,这完全取决于生成出来的代码是否可用。例如:

template<typename T>
class NamedObject
{
public:
    NamedObject(std::string &name, const T &value);

private:
    std::string &_name;
    const T _objectValue;
};

//...

int main()
{
    NamedObject<int> dog("dog", 10);
    NamedObject<int> cat("cat", 12);
    dog = cat; //编译错误。
    return 0;
}

此时,编译器将不会再为我们生成拷贝构造函数和拷贝赋值运算符,因为编译器认定默认的操作存在一定的风险:

  • 如果修改了引用的对象,那么对应的原对象以及其他通过指针或者引用指向该对象的逻辑都可能发生变化(对于指针则无妨,编译器对引用添加了额外的限制)。
  • const修饰的对象是具有二进制常量属性的,编译器无法使用默认的方法修改const对象

此时,如果想让程序正常运行,那么就必须自己提供拷贝构造函数和拷贝赋值运算符。

【注意】

  • C++编译器会为我们合成一些与类生命周期相关的函数,但是同时也会检查这些代码的合法性;对于那些生成后不合法或者有风险的代码,编译器将强迫我们手动实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值