当前位置: 首页 > news >正文

C++中的new、operator new与placement new

new operator

new operator是我们常用的new。

new 和 delete 是用来在 堆上申请和释放空间的 ,是 C++ 定义的 关键字,和 sizeof 一样。

实际 new / delete 和 malloc / free 最大的区别是,前者对于 自定义类型 除了可以开辟空间,还会调用构造和析构函数

  1. 分配内存,如果类A重载了operator new,那么将调用A::operator new(size_t )来完成,如果没有重载,就调用::operator new(size_t ),即全局new操作符来完成

  2. 调用构造函数生成类对象;

  3. 返回相应指针

1.operator new、operator delete就是对malloc和free的封装

2.operator new中调用malloc开辟空间失败后,改为抛异常处理,这种处理更符合C++处理错误的方式

new 的原理

Ⅰ. 调用 operator new 函数申请空间

Ⅱ. 在申请的空间上执行构造函数,完成对象的构造

delete 的原理

Ⅰ. 在空间上执行析构函数,完成对象中资源的清理工作

Ⅱ. 调用 operator delete 函数释放对象的空间

new T[N] 的原理

Ⅰ. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申请

Ⅱ. 在申请的空间上执行 N 次构造函数

delete[] 的原理

Ⅰ. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理

Ⅱ. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间

operator new

operator new是一个操作符,和+ -操作符一样,作用是分配空间。我们可以重写它们,修改分配空间的方式。

operator new返回值必须是void*。第一个参数必须是size_t

void* operator new (std::size_t size) throw (std::bad_alloc);  
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw(); 

在下面的例子中,我们使用重载了三个operator new方法, 并分别调用。

#include <iostream>
#include <string>
#include <malloc.h>
using namespace std;//student class
class Stu
{
public:Stu(string name, int age){cout << "call Stu class constructor" << endl; name_ = name;age_ = age;};
public:void print() const{cout << "name = " << name_ << std::endl;cout<< "age = " << age_ << std::endl;};void* operator new(size_t size){std::cout << "call operator new" << std::endl;return malloc(size);}void* operator new(size_t size, int num){std::cout << "call operator new with int" << std::endl;return malloc(size);} void* operator new(size_t size, char c){std::cout << "call operator new with char" << std::endl;return malloc(size);}      
private:string name_;int age_;
};
int main()
{Stu* stu1 = new Stu("a", 10);Stu* stu2 = new(1) Stu("a", 10);Stu* stu3 = new('c') Stu("a", 10);
}

placement new

placement new是operator new的一种重载形式,其作用是可以在指定的内存地址创建对象。

placement new返回值必须是void*。第一个参数必须是size_t, 第二个参数是void*。

void* operator new (std::size_t size, void* ptr) throw();

下面的是一个关于placement new的调用例子:

#include <iostream>
#include <string>
#include <malloc.h>
using namespace std;//student class
class Stu
{
public:Stu(string name, int age){name_ = name;age_ = age;};
public:void print() const{cout << "name = " << name_ << std::endl;cout<< "age = " << age_ << std::endl;};void* operator new(size_t size, void* p){std::cout << "placement new" << std::endl;return p;};    
private:string name_;int age_;
};
int main()
{void* stu1 = (Stu*)malloc(sizeof(Stu));new (stu1) Stu("stu1", 10);((Stu*)stu1)->print();
}

由于placement new可以在一个指定的位置创建对象,因此在STL中有很广泛的运用, 例子vector容器初始化的时候,会使用allocator申请一定的内存,当使用push_back放入对象时, 就可以使用placement new在申请的位置创建对象。

结论

对于new, operator new 和 placement new三者的区别, 我们总结如下:

new:

new是一个关键字,不能被重载。

new 操作符的执行过程如下:

  • 调用operator new分配内存 ;

  • 调用构造函数生成类对象;

  • 返回相应指针。

operator new:

operator new就像operator + 一样,是可以重载的。

如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。

同理,operator new[]、operator delete、operator delete[]也是可以重载的。

placement new:

placement new和operator new并没有本质区别。它们都是operator new操作符的重载,只是参数不相同。

placement并不分配内存,只是返回指向已经分配好的某段内存的一个指针。因此不能删除它,但需要调用对象的析构函数。

如果你想在已经分配的内存中创建一个对象,使用new时行不通的。

也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void* p实际上就是指向一个已经分配好的内存缓冲区的的首地址。

http://www.lryc.cn/news/246445.html

相关文章:

  • ElasticSearch之cat anomaly detectors API
  • Luminar Neo1.16.0(ai智能图像处理)
  • ElasticSearch之cat aliases API
  • bash编程 数组和for循环的应用
  • Python基础:标准库概览
  • C#,《小白学程序》第三课:类class,类的数组及类数组的排序
  • 建筑结构健康监测系统和传统人工监测的区别
  • 二 使用GPIO的复用功能 利用USART 实现printf()
  • C#中的警告CS0120、CS0176、CS0183、CS0618、CS0649、CS8600、CS8601、CS8602、CS8604、CS8625及处理
  • js中声明变量的关键字(const,let,var)
  • Android13 launcher循环切页
  • Java学习路线第一篇:Java基础(2)
  • 网络工程师精华篇,50种网络故障及解决方法大集合
  • Unity播放网络视频
  • SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测
  • 线性分类器--图像表示
  • 车载通信架构 —— 传统车内通信网络FlexRay(较高速度高容错、较灵活拓扑结构)
  • 如何在Ubuntu的Linux系统中安装MySQL5.7数据库
  • 基于Hadoop的区块链海量数据存储的设计与实现
  • 运行时错误/缺陷到底是什么缺陷
  • 应用Web3.0的5种方法提升你的点击量
  • 计算机服务器中了mallox勒索病毒如何处理,mallox勒索病毒解密文件恢复
  • 408—电子笔记分享
  • 【每日一题】子数组的最小值之和
  • 【docker】docker总结
  • [英语学习][3][Word Power Made Easy]的精读与翻译优化
  • 使用UIActivityViewController分享图片,没有preview
  • linux安装终端连接工具Tabby
  • Linux telnet命令详解:通过TCP/IP网络连接与管理远程机器(附实例教程和注意事项)
  • linux 磁盘管理、分区管理常用命令