c++ 内存管理二:重载(接管内存管理工具)

news/2025/2/14 8:28:45/

文章目录

      • 前言
      • 1 重载全局的 ::operator new 运算符
      • 2 重载类的 operator new 运算符
      • 3 重载类的带有额外参数的 operator new 运算符

前言

重载 operator new 运算符来自定义内存分配的行为。重载 operator new 运算符允许我们使用自定义的内存分配逻辑,例如使用池分配、内存池等。

以下是重载 operator new 运算符的几种方式:

1 重载全局的 ::operator new 运算符

void* operator new(std::size_t size) {// 自定义内存分配逻辑void* ptr = /* 自定义逻辑 */;return ptr;
}

通过重载全局的 operator new,我们可以自定义所有类的内存分配行为,注意这里一般不会这样做,因为影响太深远,涉及面广,因为程序中可能大多数类的new都是使用默认的,没有重载自身类的operator new,可能都是使用全局的 ::operator new

2 重载类的 operator new 运算符

class MyClass {
public:static void* operator new(std::size_t size) {// 自定义内存分配逻辑void* ptr = /* 自定义逻辑 */;return ptr;}
};

在类中重载 operator new 运算符,可以针对该类自定义内存分配的行为。
因为new往往是在创建对象的时候,所以不是对象的方法,应该是static。

示例代码

class Foo
{
public:int _id;long _data;string _str;public:static void* operator new(size_t size);static void  operator delete(void* deadObject, size_t size);static void* operator new[](size_t size);static void  operator delete[](void* deadObject, size_t size);	  	  Foo() : _id(0)      { cout << "default ctor. this="  << this << " id=" << _id << endl;  }Foo(int i) : _id(i) { cout << "ctor. this="  << this << " id=" << _id << endl;  }~Foo()              { cout << "dtor. this="  << this << " id=" << _id << endl;  }
};void* Foo::operator new(size_t size)
{Foo* p = (Foo*)malloc(size);  cout << "Foo::operator new(), size=" << size << "\t  return: " << p << endl;  	return p;
}void Foo::operator delete(void* pdead, size_t size)
{cout << "Foo::operator delete(), pdead= " << pdead << "  size= " << size << endl;free(pdead);
}void* Foo::operator new[](size_t size)
{Foo* p = (Foo*)malloc(size);  //crash, 問題可能出在這兒 cout << "Foo::operator new[](), size=" << size << "\t  return: " << p << endl;  return p;
}void Foo::operator delete[](void* pdead, size_t size)
{cout << "Foo::operator delete[](), pdead= " << pdead << "  size= " << size << endl;free(pdead);
}void test_overload_operator_new_and_array_new() 
{	cout << "\ntest_overload_operator_new_and_array_new().......... \n";		cout << "sizeof(Foo)= " << sizeof(Foo) << endl;{	Foo* p = new Foo(7);delete p;Foo* pArray = new Foo[5];	//無法給 array elements 以 initializer delete [] pArray;	}{	    cout << "testing global expression ::new and ::new[] \n";// 直接调用全局的 ::new 这会绕过 overloaded new(), delete(), new[](), delete[]() // 但 ctor, dtor 都会被正常调用.  Foo* p = ::new Foo(7);::delete p;Foo* pArray = ::new Foo[5];	::delete [] pArray;}
}

3 重载类的带有额外参数的 operator new 运算符

void* operator new(std::size_t size, AdditionalArgs args) {// 自定义内存分配逻辑,可以使用额外的参数void* ptr = /* 自定义逻辑 */;return ptr;
}

通过重载带有额外参数的 operator new,我们可以在内存分配过程中传递额外的参数,以便进行更复杂的内存管理。

在重载 operator new 运算符时,注意以下几点:

  • 返回值类型必须为 void*,表示分配的内存地址。
  • 第一个参数是 std::size_t size,表示要分配的内存大小。
  • 可以有额外的参数,以满足特定需求。
  • 可以使用任何自定义的内存分配逻辑,例如使用 malloc、内存池等。
  • 注意处理错误和异常情况,确保内存分配成功。

示例代码

class Foo
{
public:Foo() { cout << "Foo::Foo()" << endl;  }Foo(int) { cout << "Foo::Foo(int)" << endl;  }//(1) 这个就是一般的 operator new() 的重载void* operator new(size_t size) {cout << "operator new(size_t size), size= " << size << endl;return malloc(size);  }//(2) 这个就是标准库已经提供的 placement new() 的重载 (形式)void* operator new(size_t size, void* start) { cout << "operator new(size_t size, void* start), size= " << size << "  start= " << start << endl;return start;}void* operator new(size_t size, long extra) { cout << "operator new(size_t size, long extra)  " << size << ' ' << extra << endl;return malloc(size+extra);}void* operator new(size_t size, long extra, char init) { cout << "operator new(size_t size, long extra, char init)  " << size << ' ' << extra << ' ' << init << endl;return malloc(size+extra);}//(1) 这是对应一般的 operator delete() 的重載 void operator delete(void*,size_t){ cout << "operator delete(void*,size_t)  " << endl;  }//(2) 这是对应上述的 (2)  void operator delete(void*,void*){ cout << "operator delete(void*,void*)  " << endl;  }//(3) 这是对应上述的 (3)  void operator delete(void*,long){ cout << "operator delete(void*,long)  " << endl;  }//(4) 这是对应上述的 (4)  //如果沒有一一对应, 也不会有任何编译错误void operator delete(void*,long,char){ cout << "operator delete(void*,long,char)  " << endl; }private:int m_i;
};void test_overload_placement_new()
{cout << "\n\n\ntest_overload_placement_new().......... \n";Foo start;  //Foo::FooFoo* p1 = new Foo;           //op-new(size_t)Foo* p2 = new (&start) Foo;  //op-new(size_t,void*)Foo* p3 = new (100) Foo;     //op-new(size_t,long)Foo* p4 = new (100,'a') Foo; //op-new(size_t,long,char)Foo* p5 = new (100) Foo(1);     //op-new(size_t,long)  op-del(void*,long)Foo* p6 = new (100,'a') Foo(1); //Foo* p7 = new (&start) Foo(1);  //Foo* p8 = new Foo(1);           //}

在这里插入图片描述

//VC6 warning C4291: ‘void *__cdecl Foo::operator new(unsigned int)’
//no matching operator delete found; memory will not be freed if
//initialization throws an exception

这表示对对应的new调用的构造函数的异常不做处理。所以这里delete参数实际上是对应异常的类型。

将构造函数抛出异常,然后打印。这里要注意将调用的代码即test_overload_placement_new使用try catch包含,否则无法捕获异常。

Foo(int) { cout << "Foo::Foo(int)" << endl;  throw 1;}

可以看到,operator delete(void*,long)是执行了。
当然异常抛出以后后面的自然也就不执行了。
在这里插入图片描述


http://www.ppmy.cn/news/701739.html

相关文章

你还相信节食能减肥?

现在的姑娘们真是越来越努力了&#xff0c;她们不但工作上更努力上进&#xff0c;生活中也在努力经营好自己的形象。好形象的前提是拥有良好的体形&#xff0c;对身材不满意的她们勇于尝试各种减肥方法&#xff0c;节食减肥在她们看来最直接有效。但&#xff0c;事实真的是这样…

吃饱饱地减肥,你试过吗?

当你想减肥时&#xff0c;你可以从少吃开始。 但是你如何在不挨饿的情况下缩减你的份量呢&#xff1f;值得庆幸的是&#xff0c;你可以使用几种策略来减少卡路里&#xff0c;同时保持饥饿感。 这篇文章包含 8 个很好的技巧&#xff0c;可以减少食物的份量而不会让你更饿。 1.蔬…

胖了,也是该减减肥了

胖了&#xff0c;也是该减减肥了&#xff0c;早上开始骑自行车上班了 10几公里的路居然要骑45分钟&#xff0c;哎~~~~老了 今天才是第2天&#xff0c;以后继续努力锻炼身体 身体才是革命的本钱哦~ &#xff1a;&#xff09;

减肥日志:100天40斤!!

为了把身体从易饿模式调整成耐饿模式&#xff0c;第一天要空腹&#xff0c;不吃饭&#xff0c;只喝水&#xff1b; 空腹第1天之后&#xff0c;要坚持养成的习惯是吃的少&#xff0c;吃的慢&#xff01;&#xff01; 吃的少的秘诀是将午餐一分为二&#xff0c;一半做中餐&…

如何健康减肥

选择正确的饮水方式&#xff0c;不要每天盲目地喝太多的水。科学研究表明&#xff0c;每天喝1.5L的水是最好的&#xff0c;但这种方法并不适用于所有人。要是自己的肾脏代谢功能有问题的话&#xff0c;不要喝很多的水&#xff0c;原因是身体将无法代谢多余的水分&#xff0c;反…

减肥计划

减肥-饮食计划 周一&#xff1a; 早餐&#xff1a;白水煮蛋1个、无糖豆浆1杯; 午餐&#xff1a;冬瓜汤为主菜&#xff0c;配米饭1小碗(1两)&#xff0c;黄瓜凉菜1碟; 晚餐&#xff1a;苹果。 主打减肥菜&#xff1a;冬瓜&#xff0c;冬瓜味甘淡而性微寒&#xff0c…

阿里云外网无法访问Dcoker容器

应该是docker和linux网段冲突 1、路由策略开启转发 cat >> /etc/sysctl.conf <<EOF net.ipv4.ip_forward 1 net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-arptables 1 EOF sysctl -p 2、查看配置…

人体脂肪的形成及如何消耗

原因&#xff1a; 1、食物中的脂肪在消化道分解为脂肪酸被小肠吸收&#xff0c;进入人体后重新合成脂肪&#xff1b; 2、食物中的糖和蛋白质&#xff0c;如果摄入量超过消耗量&#xff0c;也会转化为脂肪酸&#xff0c;进一步合成脂肪&#xff0c;以脂肪形式贮存起来。 如何…