frankfan的胡思乱想

学海无涯,回头是岸

析构函数

构造函数/析构函数 this指针 new/delete

本章讲授的主要内容是C++类的构造,其中牵涉到的概念有类的构造函数与析构函数,this指针与new、delete关键字。

构造函数/析构函数

在所有面向对象的语言中,为了方便管理对象的生命周期,会在对象生成时与对象销毁时调用两个特殊的函数,构造函数,析构函数,这两个函数通常不需要用户手动调用,交由编译器调用。

当构造函数被调用时,类已经生成,但其成员变量没有被初始化,因此通常在构造函数中对类成员进行初始化,而当析构函数被调用时,则表明对象被销毁,通常在此时对对象中的资源进行释放。

#include <iostream>
class Node{
public:
  Node(){
    value = 0;
    size = 0;
    buf = new char[1024];
  }
  ~Node(){
    
    if(buf != nullptr){
      delete[] buf;
      buf = nullptr;
    }
  }
private:
  int value;
  int size;
  char *buf;
};
int main(){
  
  //定义在栈中的对象,当其出作用域后,对象便会被析构。
  Node node;//定义了一个在栈中的node对象,main函数结束时被析构
  {
    //在块作用域中定义了一个在栈中的node对象,当作用域结束,node2对象被释放
    Node node2;
  }
  return 0;
}

this指针

C++中的关键字,出现在类的非静态成员函数调用中,表示调用函数的那个具体对象地址,类型为Type * const this ,显然,这是一个指针常量,无法被赋值。也只能在类的非静态成员函数中使用。

#include <iostream>
class Node{
public:
  
  void showValue(){
    cout<<this->value<<endl;
  }
  
  //通过强制指定的方式让对象调用函数变成标准调用约定,这是this指针值被当做函数参数push入栈(不过在某些编译器中,手动指定无效)
  void __stdcall setValue(int v){
    //this的值来着ecx寄存器,类型为 Node * const this
    this->value = v;
  }
  
  Node(){
    value = 0;
    size = 0;
  }
  ~Node(){
    
  }
private:
  int value;
  int size;
};
int main(){
  Node node;
  //此函数只有一个函数参数,但是调用约定采用的是C++特有的__thiscall.
  //这种调用约定是将this指针指通过ecx寄存器传递值,因此默认情况下是无法对this指针取地址的,用__thiscall调用约定而不用__stdcall的好处在1、与_stdcall栈结构保持一致。2、优化this传值效率
  node.setValue(12);
  node.showValue();//12
  //__thiscall调用约定的this指针值被存放在ecx寄存器中,无法被修改,无法被取地址,无法被取内存值(正常途径下
  return 0;
}

new、delete

C++中,对象既可以定义在栈中,又可以定义在堆中。C++中通过new关键字来创建堆对象,返回对象的堆地址值,通过delete关键字来释放堆对象。

同样都是创建堆内存,需要与mallocfree区分开来。

malloc是C时代的函数,作用是用来创建堆空间,与面向对象的概念无关,因此malloc函数也无法创建堆对象(不会调用类的构造函数),free只是释放堆空间,不会析构对象。

#include <iostream>

class Node{
public:
	Node(){
    cout<<"node()"<<endl;
  } 
  ~Node(){
    
  }
};
int main(){
  
  //在堆中创建一个一个node对象,若不调用delete,则永远不会释放(除非进程退出
  Node *node = new Node;
  {
    Node *node2 = new Node;//即使离开作用域,node2对象也不会释放
    delete node2;
  }

  delete node;
  
  //创建12个node对象,在堆上创建对象群时会在首地址的前面4个字节中存放对象群的总大小
  Node *nodes = new Node[12];//Node()构造函数被调12次
  delete[] nodes;//只能通过这种方式释放对象群,这种语法会找到堆空间中对象群的首地址处的前4个字节,从中取出对象群的大小,从而释放对象群
	//delete nodes;闪退,通过这种方式是无法定位到正确的对象地址的,因此运行过程中出现闪退
  //delete[] nodes;释放对象群时,从后往前,高地址处的对象被先释放,低地址处的对象被后释放.
  return 0;
}

posted on 2021-12-28 00:33  shadow_fan  阅读(151)  评论(0编辑  收藏  举报

导航