84669 人が学習中
152542 人が学習中
20005 人が学習中
5487 人が学習中
7821 人が学習中
359900 人が学習中
3350 人が学習中
180660 人が学習中
48569 人が学習中
18603 人が学習中
40936 人が学習中
1549 人が学習中
1183 人が学習中
32909 人が学習中
学习是最好的投资!
原因在于优化.先来分析你的程序, a1是一个实例, a2是一个, getTest传参是传值那么会有一个Temp1, getTest又有一个return Temp2. 所以一共应该是四个对象.
但是, 编译器会有优化, 甚至在你禁止优化的时候也会有一点点优化. 比如getTest的返回值, 本来按照语义是需要调用operator=, 实际上编译器通常是直接调用CTest1(const CTest1&)这个构造函数, 把两次构造优化成1次.
operator=
CTest1(const CTest1&)
你那个代码, 把析构函数里面的cout注释掉, 就会发现只构造了3次. 因为析构函数里面什么都没有的话, 编译器开启那个优化, 对你的代码功能上就没有任何影响. 但是你开cout的话, 一旦优化掉的话, 代码的功能可能就不正确了.
你删掉析构函数里面的cout, 用gcc编译, 添加参数-O0 -fno-elide-constructors, 实际上还是四个对象.
-O0 -fno-elide-constructors
CTest1 getTestObj(CTest1 obj) { return obj; /* copy */ } int main() { CTest1 a1; // construct CTest1 a2 = /* copy */ getTestObj(a1/* copy */); return 0; }
关于返回值有一种对编译器来说省事的方式,叫做返回值优化(RVO - return value optimization)。编译器会省略一步对象的COPY构造调用,不知道LZ用的什么编译器,在gcc(4.8.3)上面是默认开启的,就是说结果是这样的:
Constructor of CTest1:0 Copy constructor of CTest1:1 Copy constructor of CTest1:2 //如果去掉注释 就会打印下面三句话 destroy id:1 destroy id:2 destroy id:0
原因在于优化.
先来分析你的程序, a1是一个实例, a2是一个, getTest传参是传值那么会有一个Temp1, getTest又有一个return Temp2. 所以一共应该是四个对象.
但是, 编译器会有优化, 甚至在你禁止优化的时候也会有一点点优化. 比如getTest的返回值, 本来按照语义是需要调用
operator=
, 实际上编译器通常是直接调用CTest1(const CTest1&)
这个构造函数, 把两次构造优化成1次.你那个代码, 把析构函数里面的cout注释掉, 就会发现只构造了3次. 因为析构函数里面什么都没有的话, 编译器开启那个优化, 对你的代码功能上就没有任何影响. 但是你开cout的话, 一旦优化掉的话, 代码的功能可能就不正确了.
你删掉析构函数里面的cout, 用gcc编译, 添加参数
-O0 -fno-elide-constructors
, 实际上还是四个对象.关于返回值有一种对编译器来说省事的方式,叫做返回值优化(RVO - return value optimization)。编译器会省略一步对象的COPY构造调用,不知道LZ用的什么编译器,在gcc(4.8.3)上面是默认开启的,就是说结果是这样的: