深入浅析C++的new和delete分享!

可以看出代码中buf1是栈内存而buf2是堆内存,这两块内存区域都是已经分配好了的内存,现在我们想把这些内存来当做CA类的对象来使用,因此我们需要对内存调用类的构造函数CA::CA()才可以,构造函数的内部实现会为内存区域填充虚表指针,这样对象才可以调用诸如foo虚函数。但是这样写代码不够优雅,那么有没有比较优雅的方法来实现在一块已经存在的内存上来构建对象呢? 答案就是 placement技术。 C++中的仍然是使用new和delete来实现这种技术。new和delete除了实现默认的操作符外还重载实现了如下的操作符函数:

  void* operator new(size_t size, void *p)  {   return p;  }  void* operator new[](size_t size, void *p)  {   return p;  }  void operator delete(void *p1, void *p2)  {   // do nothing..  }  void operator delete[](void *p1, void *p2)  {   // do nothing..  }

我们称这四个运算符为 placement new 和 placement delete  。通过这几个运算符我们就可以优雅的实现上述的功能:

  char buf1[100];  CA *p1 = new(buf1) CA(10); //调用 operator new(size_t, void*)  p1->foo();  char *buf2 = new char[sizeof(CA)];  CA *p2 = new(buf2) CA(20);  //调用 operator new(size_t, void*)  p2->foo();  p1->~CA();  operator delete(p1, buf1); //调用 operator delete(void*, void*)  p2->~CA();  operator delete(p2, buf2); //调用 operator delete(void*, void*)  delete[] buf2;

上面的例子里面发现通过placement new可以很优雅的在现有的内存中构建对象,而析构时不能直接调用delete p1, delete p2来销毁对象,必须人为的调用析构函数以及placement delete 函数。并且从上面的placement delete的实现来看里面并没有任何代码,既然如此为什么还要定义一个placement   delete呢? 答案就是C++中的规定对new和delete的运算符重载必须是要成对实现的。而且前面曾经说过对delete的使用如果带了operator前缀时就只是一个普通的函数调用。因此为了完成析构以及和new操作符的匹配,就必须要人为的调用对象的析构函数以及placement delete函数。
除了上面举的例子外placement技术的使用还可以减少内存的频繁分配以及提升系统的性能。

  void main()  {    for (int i = 0; i < 10000; i++)    {     CA *p = new CA(i);     p->foo();     delete p;    }  }

例子里面循环10000次,每次循环都创建一个堆内存对象,然后调用虚函数foo后再进行销毁。最终的结果是程序运行时会进行10000次的频繁的堆内存分配和销毁。很明显这是有可能会影响系统性能的而且还有可能发生堆内存分配失败的情况。而如果我们借助placement 技术就可以很简单的解决这些问题。

  void main()  {    char *buf = new[](sizeof(CA));    for (int i = 0; i < 10000; i++)    {     CA *p = new(buf) CA(i);     p->foo();     p->~CA();     operator delete(p, buf);    }    delete[] buf;  }

上面的例子里面只进行了一次堆内存分配,在循环里面都是借助已经存在的内存来构建对象,不会再分配内存了。这样对内存的重复利用就使得程序的性能得到非常大的提升。

new和delete运算符重载

发现一个很有意思的事情就是越高级的语言就越会将一些系统底层的东西进行封装并形成一个语言级别的关键字来使用。比如C++中的new和delete是用于构建和释放堆内存对象的关键字,又比如go语言中chan关键字是用于进行同步或者异步的队列数据传输通道。

C++语言内置默认实现了一套全局new和delete的运算符函数以及placement new/delete运算符函数。不管是类还是内置类型都可以通过new/delete来进行堆内存对象的分配和释放的。对于一个类来说,当我们使用new来进行构建对象时,首先会检查这个类是否重载了new运算符,如果这个类重载了new运算符那么就会调用类提供的new运算符来进行内存分配,而如果没有提供new运算符时就使用系统提供的全局new运算符来进行内存分配。内置类型则总是使用系统提供的全局new运算符来进行内存的分配。对象的内存销毁流程也是和分配一致的。

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/482206.html

(0)
上一篇 2020年11月9日
下一篇 2020年11月9日

精彩推荐