1. 测试代码:

#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;if (void* ptr = malloc(size))  return ptr;elsethrow bad_alloc();
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}int main()
{int* ptr = new int(10);delete ptr;cout << endl << "------------" << endl << endl;ptr = new(20) int(10);delete ptr;return 0;
}

输出结果:

分析:

从上面的结果可以看出,new int(10);直接先调用 operator new(size_t size); 由于int没有构造函数,在那块内存上调用int的构造函数; 在delete ptr; 的时间直接调用 operator delete(void * ptr);这个函数

new(20) int(10);的时候,则调用重载版本的 operator new(size_t size, int flag); 而该函数有调用了 operator new(size_t size); 函数,释放的时候delete ptr;还是直接只调用operator delete(void * ptr);(注:这里初步提出为啥不调用operator delete(void * ptr, int flag); 这个函数来释放ptr ???因为它的用途不在这,而在于下面将要讲的。

2. 测试代码:

#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//类中定制的operator new会覆盖全局的函数,但可以通过简单的调用全局的函数来实现调用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //调用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}static void operator delete(void* ptr, int flag){cout << "Override operator delete of Base: " << flag << endl;operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}

输出结果:

2. 若是不给Base类重载 static void operator delete(void * ptr, int flag);这个函数,结果则如下图:

#include <iostream>
#include <new>
#include <cstring>
#include <cstdlib>
using namespace std;void* operator new(size_t size)
{cout << "global Override operator new" << endl;void* ptr = malloc(size);return ptr;
}void* operator new(size_t size, int flag)
{cout << "global Override operator new: " << flag << endl;return (::operator new(size));
}void operator delete (void* ptr)
{cout << "global Override operator delete" << endl;free(ptr);ptr = nullptr;
}void operator delete (void* ptr, int flag)
{cout << "Override operator delete: " << flag << endl;::operator delete(ptr);ptr = nullptr;
}class Base
{
public:Base(){cout << "Base construct" << endl;throw 2;}~Base(){cout << "Base destructor" << endl;}//类中定制的operator new会覆盖全局的函数,但可以通过简单的调用全局的函数来实现调用static void* operator new(size_t size){cout << "operator new of Base" << endl;return ::operator new(size); //调用全局的operator new}static void* operator new(size_t size, int flag){cout << "Override operator new of Base: " << flag << endl;return operator new(size);}static void operator delete(void* ptr){cout << "Operator delete of Base" << endl;::operator delete(ptr);}int x;int y;
};
int main()
{try{Base* bptr = new(20) Base;}catch (...){cout << "catch a exception" << endl;}return 0;
}

输出结果:

二、定位new表达式

operator new和operator delete和alloctor类的allocate和deallocate很像,都是负责分配和释放内存的函数,但是对于operator new分配的内存空间我们无法使用construct函数构造对象,我们应该使用new的定位new形式构造对象。

1. 测试代码:

#include <iostream>
#include <new>
using namespace std;const int chunk = 16;
class Foo
{
public:int val() { return _val; }Foo() { _val = 0; }
private:int _val;
};//预分配内存,但没有Foo对象
char* buf = new char[sizeof(Foo) * chunk];
int main(void)
{//在buf中创建一个Foo对象Foo* pb = new (buf) Foo;//检查一个对象是否被放在buf中if (pb->val() == 0){cout << "new expressio worked!" << endl;}//到这里不能再使用pbdelete[] buf;return 0;
}

placement new的作用就是:创建对象但是不分配内存,而是在已有的内存块上面创建对象。用于需要反复 创建并删除的对象上,可以降低分配释放内存的性能消耗。定位new表达式(placement new expression),允许程序员将对象创建在已经被分配好的内存中,new表的式的形式如下:

new (place_address) type
new (palce_address) type (initializer-list)

【Note】:

  • 当只传入一个指针类型的实参时,定位new表达式构造对象但是不分配内存,这个指针没有要求,甚至可能是一个不是一个指向动态内存的指针
  • 调用析构函数会销毁对象,但是不会释放内存。

2. 测试代码:

#include <iostream>
using namespace std;
char addr1[100];
int main()
{cout << "******定位new表达式演示***by David***" << endl;char addr2[100];char *addr3 = new char[100];cout << "addr1 = " << (void*)addr1 << endl;cout << "addr2 = " << (void*)addr2 << endl;cout << "addr3 = " << (void*)addr3 << endl;int *p = nullptr;p = new(addr1)int;  把内存分配到静态区*p = 1;cout << (void*)p << "  " << *p << endl;p = new(addr2)int; 把内存分配到栈区*p = 2;cout << (void*)p << "  " << *p << endl;p = new(addr3)int;  //把内存分配到堆区*p = 3;cout << (void*)p << "  " << *p << endl;return 0;
}

输出结果:

参考资料

  • 定制自己的new和delete:operator new 和 operator delete
  • 特殊的工具和技术

【C++ Primer | 19】控制内存分配相关推荐

  1. C++ Primer 5th笔记(chap 19 特殊工具与技术)控制内存分配

    1. new void operator new (size_t, void ) ;//不允许重新定义这个版本 string *sp = new string("a value") ...

  2. iOS内存分配与五大区域

    目录: 参考的博客: iOS内存的五大区域 : 栈区(stack) 堆区(heap): 全局区(又称静态区)(static): 文字常量区: 程序代码区: Allocations模版: 虚拟内存简介: ...

  3. JVM:自动内存管理-垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 一.概述 Java堆和方法区这两个区域有着很显著的不确定性: 1.一个接口的多个实现类需要的内存 ...

  4. 控制C++的内存分配

    在嵌入式系统中使用C++的一个常见问题是内存分配,即对new 和 delete 操作符的失控. 具有讽刺意味的是,问题的根源却是C++对内存的管理非常的容易而且安全.具体地说,当一个对象被消除时,它的 ...

  5. 《C++ Primer Plus》读书笔记之十—类和动态内存分配

    第12章 类和动态内存分配 1.不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存.可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的 ...

  6. C++ Primer Plus学习(十一)——类和动态内存分配

    类和动态内存分配 动态内存和类 静态类成员 特殊成员函数 string类的改进 构造函数中的new 返回对象 指向对象的指针 成员初始化列表(member initializer list) 动态内存 ...

  7. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,G ...

  8. 【嵌入式开发】C语言 内存分配 地址 指针 数组 参数 实例解析

    . Android源码看的鸭梨大啊, 补一下C语言基础 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/detai ...

  9. JVM的垃圾回收与内存分配

    Java是一种内存动态分配和垃圾回收技术的一种语言,不需要显示的进行对象内存的分配,这一切操作都是由JVM来完成的,由于Java是"一切皆对象"的,所以对于内存分配的优化与速度非常 ...

最新文章

  1. SAP零售行业解决方案初阶 7 - 自动补货
  2. python的第三方库-Python 的第三方库到底行不行啊?
  3. Linux中的ftp命令怎么写,linux下使用ftp命令
  4. ArcGIS斜坡单元工具箱
  5. SpringBoot + AOP 统一处理日志
  6. sublime text3 中 python3编译出现中文乱码解决方法
  7. 运用tms320c54x汇编语言编写定点数运算,浮点数运算程序,运用TMS320C54x汇编语言编写定点数运算、浮点数运算程序...
  8. Spanner如何实现事务?
  9. ssm-学子商城-项目第三天
  10. android 刷入 windows,安卓技术宅系列之安卓手机刷Windows98
  11. JDK/ADB环境变量配置
  12. python远程连接windows_python winrm 连接windows
  13. 华南师范大学计算机学院保研,保研学霸专访
  14. 华为 2015 机试 输出:数字后面的连续出现的(2个或多个)相同字符(数字或者字符),删去一个,非数字后面的不要删除,例如,对应输出为:33aabb55pin。...
  15. 类的加载、连接和初始化
  16. 一般来说仿制一个网站大概需要多少钱呢
  17. 案例:Java多态实现饮料购买咖啡、可乐、矿泉水2.0
  18. 铁矿石大幅反弹,棉花认购大涨2倍,YP09继续探底2022.4.28
  19. 【开发】前端工程——ReactJS
  20. 微信文件传输助手网页版

热门文章

  1. 【Hexo】deploy出错的解决方法
  2. (译)利用ASP.NET加密和解密Web.config中连接字符串
  3. MyBatis ResultMap(2)
  4. vba将select的值直接赋给变量
  5. 初来乍到!各位博客朋友多多支持!
  6. aix内核是linux,查看Linux及AIX硬件信息方法总结
  7. oracle 老白,老白学编程 - Netdata学习 - numa
  8. 计算机专业学生求职信500字,计算机专业求职信500字范文
  9. python concat_python中merge、concat用法
  10. numpy维度交换_“lazy”的transpose()函数——从numpy 数组的内存布局讲起