写在前面:
在拷贝初始化(也就是用等号初始化,注意使用拷贝构造函数创建一个新的对象不属于拷贝初始化)过程中,编译器可以(但不是必须)跳过拷贝构造函数或者移动构造函数,直接创建对象。
1 string null_book="999"; 2 //可以改写为 3 string null_book("999");
这里面”999“隐式的转换为string对象,例如:string temp("999");,然后执行拷贝构造函数:string null_book=temp;
但是者里面的拷贝构造被忽略掉了。
这里面举个黑马程序员的例子:
1 class Person 2 { 3 public: 4 Person() 5 { 6 cout << "Person的默认构造函数调用" 7 << "地址为:" 8 << this 9 << endl; 10 } 11 Person(int age):age_(age) 12 { 13 cout << "Person有参构造函数调用" 14 << "地址为:" 15 << this 16 << endl; 17 } 18 Person(const Person& p) 19 { 20 cout << "Person的拷贝构造函数调用" 21 <<"地址为:" 22 <<this 23 << endl; 24 25 } 26 ~Person() 27 { 28 cout << "Person的析构函数调用" 29 << "地址为:" 30 << this 31 << endl; 32 } 33 int age_; 34 }; 35 36 Person dowork() 37 { 38 Person p3; 39 return p3; 40 } 41 void test03() 42 { 43 Person p4 = dowork(); 44 } 45 46 int main() 47 { 48 test03(); 49 system("pause"); 50 return 0; 51 }
运行结果为:
在没有运行之前个人猜测运行结果会是这样的:
首先p3在创建的时候会调用默认构造。
然后在运行return语句的时候系统会创建一个临时的对象temp会接收到p3此时调用拷贝构造
然后将p3析构掉
然后,在test03函数中Person p4 = dowork();会调用拷贝构造函数,将temp拷贝给p4
然后当test03执行结束后会析构掉p4。
(这里面我有个问题就是temp什么时候被析构掉呢,黑马程序员的代码中也没有解释p'何时被析构掉,我想这个应该是返回值的知识,也就是返回的时候创建这个临时的temp的生命周期到底是多久,是在调用点将值传递给接收的变量吗)。
然而运行结果却只有默认构造和它的析构也就是对象p3。
这里面在返回的时候编译器采用了返回值优化,也就是没有创建那个临时的对象temp,是直接将p3直接返回到调用dowork的地方,中间没有生成temp的过程,因此这一次的拷贝构造就没了,然后执行Person p4 =dowork();时采用的是拷贝初始化,这个地方编译器直接跳过拷贝构造也不会调用拷贝构造,所以这一步也没有发生拷贝构造。
以上是个人的理解
再来看一个例子:
也就是对象在值传递的时候会发生拷贝构造,注意这里是实参赋值给形参发生的拷贝构造,不是拷贝初始化。
1 class Person 2 { 3 public: 4 Person() 5 { 6 cout << "Person的默认构造函数调用" 7 << "地址为:" 8 << this 9 << endl; 10 } 11 Person(int age):age_(age) 12 { 13 cout << "Person有参构造函数调用" 14 << "地址为:" 15 << this 16 << endl; 17 } 18 Person(const Person& p) 19 { 20 cout << "Person的拷贝构造函数调用" 21 <<"地址为:" 22 <<this 23 << endl; 24 25 } 26 ~Person() 27 { 28 cout << "Person的析构函数调用" 29 << "地址为:" 30 << this 31 << endl; 32 } 33 int age_; 34 }; 35 void test02(Person p2) 36 { 37 38 } 39 40 int main() 41 { 42 Person p1; 43 test02(p1); 44 system("pause"); 45 return 0; 46 }