C++析构函数顺序问题

啊大1号 2018-06-01 10:57:49
#include <iostream>  
using namespace std;

class Complex
{
private:
double m_real;
double m_imag;
int id;
static int counter;
public:
// 无参数构造函数
Complex(void)
{
m_real = 0.0;
m_imag = 0.0;
id = (++counter);
cout << "Complex(void):id=" << id << endl;
}
// 复制构造函数(也称为拷贝构造函数)
Complex(const Complex & c)
{
// 将对象c中的数据成员值复制过来
m_real = c.m_real;
m_imag = c.m_imag;
id = (++counter);
cout << "Complex(const Complex&):id=" << id << " from id=" << c.id << endl;
}
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
~Complex()
{
cout << "~Complex():id=" << id << endl;
}
};
int Complex::counter = 0;
Complex test1(const Complex& c)
{
return c;
}
Complex test2(const Complex c)
{
return c;
}

int main()
{
Complex a, b;

test1(a);
test2(a);
return 0;
}


VS2015输出:

g++输出:

请问为什么析构函数顺序会不同(见红框处)。
...全文
1348 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
啊大1号 2018-06-03
  • 打赏
  • 举报
回复
引用 8 楼 goldenhawking 的回复:
五楼说的对,编译器的特性导致的。gnu的更为学院派,比较严格。
谢谢
啊大1号 2018-06-03
  • 打赏
  • 举报
回复
引用 9 楼 weixin_42325834 的回复:
[quote=引用 7 楼 a3192048 的回复:] [quote=引用 5 楼 weixin_42325834 的回复:] 楼上说的对,4是形式参数,也就是函数内部的一个临时变量,5是返回值,原则上这两个变量所在的栈空间都是由调用函数在调用之前分配出来的,然后在调用结束时,因为反回值没有被引用,所以分配的空间全部回收,栈上的变量全部被析构。我的理解这个时候析构的顺序是由栈回收时地址的顺序决定的。所以原则上讲临时变量的析构顺序是没有保证的,没有先构造则后析构的法则。
谢谢,虽然临时变量析构顺序对整体代码没影响,但我认为g++编译器实现的更好,哪怕临时变量顺序无影响也遵从先构造后析构;VS这么实现总感觉有一点点别扭。[/quote] 我觉得其实编程语言应该这样理解,第一要遵守的是语言本身定义的标准,其次是改革编译器和平台上变成语言所表现出的差异性。有一些看似有道理的特性之所以没有被列入到语言自身标准中有不同的原因,比如难以实现,或者考虑后向兼容的问题,等等。所以对于语言自身标准之外的特性应该尽量不使用,否则就有移植和系统或者工具升级的问题。[/quote] 嗯嗯
书香门第 2018-06-03
  • 打赏
  • 举报
回复
引用 7 楼 a3192048 的回复:
[quote=引用 5 楼 weixin_42325834 的回复:] 楼上说的对,4是形式参数,也就是函数内部的一个临时变量,5是返回值,原则上这两个变量所在的栈空间都是由调用函数在调用之前分配出来的,然后在调用结束时,因为反回值没有被引用,所以分配的空间全部回收,栈上的变量全部被析构。我的理解这个时候析构的顺序是由栈回收时地址的顺序决定的。所以原则上讲临时变量的析构顺序是没有保证的,没有先构造则后析构的法则。
谢谢,虽然临时变量析构顺序对整体代码没影响,但我认为g++编译器实现的更好,哪怕临时变量顺序无影响也遵从先构造后析构;VS这么实现总感觉有一点点别扭。[/quote] 我觉得其实编程语言应该这样理解,第一要遵守的是语言本身定义的标准,其次是改革编译器和平台上变成语言所表现出的差异性。有一些看似有道理的特性之所以没有被列入到语言自身标准中有不同的原因,比如难以实现,或者考虑后向兼容的问题,等等。所以对于语言自身标准之外的特性应该尽量不使用,否则就有移植和系统或者工具升级的问题。
书香门第 2018-06-02
  • 打赏
  • 举报
回复
楼上说的对,4是形式参数,也就是函数内部的一个临时变量,5是返回值,原则上这两个变量所在的栈空间都是由调用函数在调用之前分配出来的,然后在调用结束时,因为反回值没有被引用,所以分配的空间全部回收,栈上的变量全部被析构。我的理解这个时候析构的顺序是由栈回收时地址的顺序决定的。所以原则上讲临时变量的析构顺序是没有保证的,没有先构造则后析构的法则。
  • 打赏
  • 举报
回复
五楼说的对,编译器的特性导致的。gnu的更为学院派,比较严格。
啊大1号 2018-06-02
  • 打赏
  • 举报
回复
引用 5 楼 weixin_42325834 的回复:
楼上说的对,4是形式参数,也就是函数内部的一个临时变量,5是返回值,原则上这两个变量所在的栈空间都是由调用函数在调用之前分配出来的,然后在调用结束时,因为反回值没有被引用,所以分配的空间全部回收,栈上的变量全部被析构。我的理解这个时候析构的顺序是由栈回收时地址的顺序决定的。所以原则上讲临时变量的析构顺序是没有保证的,没有先构造则后析构的法则。
谢谢,虽然临时变量析构顺序对整体代码没影响,但我认为g++编译器实现的更好,哪怕临时变量顺序无影响也遵从先构造后析构;VS这么实现总感觉有一点点别扭。
啊大1号 2018-06-02
  • 打赏
  • 举报
回复
引用 4 楼 zbplusplus 的回复:
4是参数,5是返回值,析构的时候谁先谁后没有区别,都不可能再被使用。
谢谢大神
赵4老师 2018-06-01
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
啊大1号 2018-06-01
  • 打赏
  • 举报
回复
引用 1 楼 zhao4zhong1 的回复:
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
赵老师在水经验么

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧