c++中构造函数初始化列表和赋值操作的区别
1.什么是函数初始化和赋值操作vectorint inorderTraversal(TreeNode* root); vectorint arr; int idx; ... // 初始化列表方式初始化//inorderTraversal(root)是对arr进行相应的赋值操作进行函数处理再将返回值赋值给arr BSTIterator(TreeNode* root): idx(0), arr(inorderTraversal(root)) {} // 函数体内赋值方式先默认构造再赋值 BSTIterator(TreeNode* root) { idx 0; arr inorderTraversal(root); }即初始化列表初始化construct对象刚分配内存时直接创建成员并赋予初始值。构造函数 {} 内赋值赋值assign成员已经通过默认构造函数创建完毕随后覆盖修改值。2.区别1.执行时机不同这两个方式从开始出生到完成都要经历四个时期1.分配对象内存2.初始化列表执行成员诞生阶段3.进入构造函数{}4.执行函数体内赋值而很明显里面的赋值操作初始化列表早于构造函数体执行2.性能差异如果以上的有点讲述有点模糊那么可以通过性能差异来进行相应的理解用以上面代码中的vectorint arr举例初始化列表方式arr(传入数组)→直接调用拷贝构造函数一步成型而函数内赋值方式你需要先调用vector无参默认构造创建空数组再调用operator赋值销毁原有内容、分配新内存 多一次构造 析构开销3.有些成员只能写在初始化列表不能函数内赋值我认为最值得记住的是这条有些成员你无法在函数内部赋值分别是1.const常量成员 2.引用类型成员 3.没有无参构造的自定义类成员 4.父类构造函数调用//1.常量 class A{ const int x; public: A(){ x 10; } // ❌ 错误const不能赋值 A():x(10){} // ✅ 正确 }; //2.引用类型 class A{ int r; public: A(int a):r(a){} // ✅ }; //3.没有无参构造的自定义类成员 class Person{ public: Person(int a){} // 没有无参构造 }; class Test{ Person p; public: Test(){ p Person(5); } // ❌ 编译器尝试调用Person()不存在报错 Test():p(5){} // ✅ }; //当然 如果你可以这样写骗过编译器但要小心出现指针问题 class Test{ Person* p; // 指针属于内置类型不需要调用Person构造函数 public: Test(){ Person q(5); p q; // 可以编译通过但是存在悬垂指针问题 } }; //4.父类构造函数调用类是于继承4.初始化列表会存在顺序陷阱class Test{ int a; int b; public: Test():b(10), a(b){} // 先初始化a此时b还未初始化a拿到垃圾值 //书写顺序 b,a实际初始化顺序 a,b产生 bug。 };注意1.如果你既使用了初始化列表又开启了赋值操作那么你的赋值操作会覆盖你的初始化列表里面的值这是因为先后他们赋值的先后顺序问题2.你肯定已经注意到了初始化列表有很多的优点如果你要求性能很高的话 我就推荐初始化列表尤其成员是自定义对象、容器vector,string提升性能const、引用成员需要调用带参构造的成员变量但要小心他们初始化的顺序问题