世界观崩坏

这个地方记叙了一些因为基础不牢靠而导致地动山摇的问题。希望引以为戒。

默认拷贝构造函数

一直以为C++的默认拷贝构造函数针对任何对象都是基于二进制拷贝的。具体项目中,也经常因为没有显式指定拷贝构造函数出现各种Crash的现象。于是我始终把这点作为信条。然而今天跟人讨论问题,才发现标准中针对non-trivial的对象会自动生成逐成员的默认拷贝构造,而只有trivial的对象会产生位拷贝构造。

根据定义类型内含成员的不同,有两类默认拷贝构造函数:

一、平凡的拷贝构造函数

直接拷贝内存,类似于调用std::memmove,要求自定义类型满足:

  • 没有自定义的拷贝构造函数;
  • 没有虚函数;
  • 没有对父类的虚继承;
  • 父类的拷贝构造函数也是平凡的;
  • 所有非静态成员、非静态成员数组的拷贝构造函数都是平凡的;
  • 不含任何非静态易变(volatile)变量(since c++14);

二、非平凡的默认拷贝构造函数

声明拷贝构造函数为default(函数的签名得与默认的一致)或者不声明拷贝构造函数但是程序中用到了(ORD-used)的话,编译器应当自动生成非平凡的拷贝构造函数。

  • 对于union类型,会生成一个直接拷贝内存的拷贝构造函数。
  • 对于自定义类型,自动生成的拷贝构造函数按初始化的顺序依次调用各个直接父类的拷贝构造函数、各个非静态成员变量的拷贝构造函数。

特别的,当类型有自定义的析构函数或者自定义的拷贝赋值运算符时,标准不推荐编译器自动生成默认拷贝构造函数。

三、特殊情况:不给拷贝构造函数

只要满足一下任一条件,拷贝构造函数就为未定义或者标记为delete

  • 父类或者非静态成员变量的拷贝构造函数无法被访问
  • 父类的析构函数无法访问
  • 存在自定义的移动构造函数或者移动赋值函数
  • 作为union,类型的某种“样貌”的拷贝构造函数非平凡
  • 含有右值引用的成员变量

四、更加特殊的情况:拷贝构造过程直接被优化掉(跳过)

标准允许将拷贝构造过程省略,即使拷贝构造过程存在副作用。比如函数返回的右值赋值给左值的拷贝构造过程就有可能被省略。

引用:https://www.zhihu.com/question/33042755/answer/55885825

于是发现一直错怪了JCE,在生成的C++文件中不自带拷贝构造也是理所当然的,因为根本不需要啊!

chu's box · 浙ICP备14006917号