12-05构造析构

构造。析构函数的出现时机

对象生成时会自动调用构造函数,但由于不同作用域的对象生命周期不同,构造函数出现的时机也不同,那么只要知道了对象的生命周期,便可以推断出构造函数的调用时机。

局部对象

当对象产生时,便可能引发构造函数,一般来说进入对象的作用域时,编译器会产生构造函数的代码,由于构造函数属于成员函数,因此在调用过程中需要传递this指针,构造函数调用结束后,会返回this指针,这个返回的this指针就是构造函数的一个特征,所以局部对象的构造满足两个条件:

  • 该成员函数是这个对象在作用域调用的第一个成员函数
  • 这个函数返回this指针

出作用域时调用析构函数,同样要传递this指针.

堆对象

堆重要的是识别申请和使用,申请用到malloc函数,malloc只负责申请空间,不会调用构造函数,而new则是封装了malloc和调用构造的动作。而识别构造的中点在于new产生的汇编代码会有明显特征:

je
........   ;构造,或构造的内联
jmp

堆对象的析构要使用者主动使用delete

参数对象

当对象作为参数的时候,会调用拷贝构造,拷贝构造的参数为对象的引用,对象作为参数的时候,会出发拷贝构造。

返回对象

对象时使用到拷贝构造

  • 临时对象:用来说明作用域,遇到分号就析构了

      pTest = &GetObj();  // 产生临时对象
      CTest t3 = GetObj(); // 不产生临时对象, 算拷贝构造
    
  • 无名对象:作用域跟着引用的作用域

          CTest& refTest = GetObj()    //这里产生无名对象
    

全局对象

几个代理函数:

  • $E4: 为了统一函数指针,方便_initterm中循环调用函数指针

  • $E1:负责传递采纳数,获得返回值并处理

    构造函数的$E1有返回值但用户无权调度
    
  • $E3:调用atexit注册$E2

  • $E2:析构代理,调用析构函数,因为atexit是c约定,析构是thiscall,只能在种种包一层调用


    图片.png

    想要找全局对象,只需要在ida里找到那里引用的了atexit函数就可以找到所有全局对象(正常情况)

静态对象

关键看标志,标志判断的地方会有一个跳转,跳过的代码就是注册析构

全局和静态对象析构的过程都在出main函数后有exit内的doexit来反向循环调用构造时注册的析构代理函数,先构造的后调用

对象数组

CTest *aryObj = new CTest[8];

在对象数组的前4个字节放元素个数,为的是给delete准备
在delete的时候会push一个数字,这个数字用位来表示作用

第0位:是否释放空间
第1位: 是否是对象数组

你可能感兴趣的:(12-05构造析构)