c++ new delete 详解

详解

  • c语言中使用malloc/calloc/realloc/free进行动态内存分配,malloc/calloc/realloc用来在堆上分配空间,free将申请的空间释放掉。

这里要注意的一点是,为什么分配了空间之后,必须要用户手动去free掉呢,是因为malloc、calloc、realloc都是在堆上分配的,堆上分配的空间必须由用户自己来管理,如果不释放,就会造成内存泄漏。而栈上分配的空间是由编译器来管理的,具有函数作用域,出了函数作用域后系统会自动回收,不由用户管理,所以不用用户显式释放空间。

  • c++中是通过new和delete操作符进行动态内存管理的。

  • 对指向不使用 new 分配的指针使用 delete 将产生不可预知的结果。 但是,可以对值为 0 的指针使用 delete。 此设置意味着,当 new 失败并返回 0 时,删除已失败 new 操作的结果不会造成损害

  • delete 运算符的结果类型为 void,因此它不返回值
  • new和delete既是C++中的关键字也是一种特殊的运算符
void* operator new(size_t size);
 void* operator new[](size_t size);
 void operator delete(void *p);
 void operator delete[](void *p);
  • new和delete不仅承载着内存分配的功能还承载着对象构造函数的调用功能,因此上面的对象创建代码其实在编译时会转化为如下的实现:
CA *p1 = new CA;
等价于:
CA *p1 = operator new(sizeof(CA)); //分配堆内存
CA::CA(p1); //调用构造函数


delete p1;
等价于:
CA::~CA(p1);
operator delete(p1);
  • new和delete操作其实是分别进行了2步操作:1.内存的分配,2.构造函数的调用;3.析构函数的调用,4.内存的销毁。所以当对象是从堆内存分配时,构造函数执前内存就已经完成分配,同样当析构函数执行完成后内存才会被销毁。

new运算符

  • 是使用new运算符将对象建立在堆空间中。这个过程分为两步,
  • 第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;

- 第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。

new operator 和 operator new是不一样的??
- https://blog.csdn.net/youdianmengxiangba/article/details/8233651

operator new

  • 原型:void* operator new(size_t size);
  • 返回值类型是void*,由于这个函数返回一个未经处理(raw)的指针。==未初始化的内存==。
  • 你能添加额外的參数重载函数operator new,可是==第一个參数类型必须是size_t==。
  • 就象malloc一样,operator new的职责仅仅是分配内存。
  • 将operator new重载为成员函数 自动就是static的函数。并没有显示的将operator new 操作符重载为static方法但是编译器会加上static
    因为operator new是用来给对象分配空间的,此时对象还没有被构造也就不能够使用到this信息,与对象绑定也没有意义。

placement new

  • placement new 是重载operator new的一个标准、全局的版本,它不能够被自定义的版本代替
  • void *operator new( size_t, void *p ) throw() { return p; }
  • 其结果是允许用户把一个对象放到一个特定的地方,达到调用构造函数的效果。和其他普通的new不同的是,它在括号里多了另外一个参数
  • 可以在分配好的栈空间上创建对象也可以在创建好的堆空间上创建对象。

- 已经被分配可是尚未处理的的(raw)内存,你须要在这些内存中构造一个对象。你能够使用一个特殊的operator new ,它被称为placement new。

new operator

  • 我们通常讲的new是指的是new operator
  • 我们在使用new operator的时候,实际上是执行了三个步骤
  • 不能被重载,其行为总是一致的
  • 这个操作符就象sizeof一样是语言内置的。你不能改变它的含义,它的功能总是一样的。
  • new操作符做两件事,分配内存+调用构造函数初始化。
  • 假设传递给placement new的raw内存是自己动态分配的(通过一些不经常使用的方法),假设你希望避免内存泄漏,你必须释放它
  • 如果传递给placement new的原始内存不是动态分配的就没必要delete 只需要调用对象的析构函数。比如这块内存是在栈上的。

总结

  • 你想在堆上建立一个对象,应该用new操作符。它既分配内存又为对象调用构造函数。
  • 假设你只想分配内存,就应该调用operator new函数;它不会调用构造函数。
  • 假设你想定制自己的在堆对象被建立时的内存分配过程,你应该写你自己的operator new函数。然后使用new操作符,new操作符会调用你定制的operator new。
  • 假设你想在一块已经获得指针的内存里建立一个对象。应该用placement new。

猜你喜欢

转载自blog.csdn.net/zhc_24/article/details/81183092
今日推荐