学习是最好的投资!
原因在于优化.先来分析你的程序, 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)上面是默认开启的,就是说结果是这样的: