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

news/2024/7/20 15:57:56 标签: c++, 内存管理, new

文章目录

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

前言

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

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

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

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

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

new__19">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;
	}
}

new__114">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::Foo

  	Foo* 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参数实际上是对应异常的类型。

将构造函数抛出异常,然后打印。

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

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


http://www.niftyadmin.cn/n/1009221.html

相关文章

樽海鞘群算法(SSA)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

Java-数据结构(一)

这里写目录标题 前言一、为什么需要数据结构&#xff1f;1、低效的操作2、占用过多的内存空间3、困难的数据操作 二、枚举&#xff08;Enumeration&#xff09;1、定义2、关键字3、适用场景 三、 位集合&#xff08;BitSet&#xff09;1、定义2、方法3、适用场景 四、向量&…

(五)kafka从入门到精通之topic介绍

1、kafka简介 Kafka是一个流行的分布式消息系统&#xff0c;它的核心是一个由多个节点组成的分布式集群。在Kafka中&#xff0c;数据被分割成多个小块&#xff0c;并通过一些复杂的算法在节点之间传递。这些小块被称为Kafka Topic。 2、topic知识 一个Topic是一组具有相同主题的…

测试5年,自认为工作水平不错,晚1年入职的同事现在凭什么是我领导?

有一个学员问我&#xff1a; “工作了快5年&#xff0c;一直想把自己锻炼成真正可以担当起领导者这个位置的人&#xff0c;每次汇报工作都准备很久&#xff0c;也打很久草稿和腹本。 但是到了汇报的时候&#xff0c;脑子就开始空白&#xff0c;说话没有章法&#xff0c;思路又变…

iview input组件clearable清空属性无法清空双向绑定值的原因解决

最近在使用iview新版本 input组件时&#xff0c;刚开始发现使用v-modal绑定的值&#xff0c;在点击clearable清除input框内容时&#xff0c;再次搜索发现参数还是没有被清掉 于是仔细查看代码的细节&#xff0c;才发现问题所在&#xff1a; 原来我绑定的参数的中文名称&#x…

使用ioctl扫描wifi信号获取AP的essid、mac地址等属性

使用 wifi 是一件再平常不过的是事情,有很多 wifi 工具可以帮助你扫描附近的 wifi 信号,测试信号强度等,但如何通过编程来操作 wifi 却鲜有文章涉及;本文立足实践,不使用任何第三方库,仅使用 ioctl 扫描附近的 wifi 信号,并获取这些 AP 的 ESSID、MAC 地址、占用信道和工…

Multiple HTTP implementations were found on the classpath错误的解决方法

当我们的项目中集成了多个AWS相关Jar包时,有可能就会遇到这个错误: 错误信息: There is an issue with the connector Code: InvalidInput.InvalidConnectorConfiguration Message: The connector configuration is invalid. Message: Multiple HTTP implementations were f…

cf1715 D 贪心

题意&#xff1a;https://codeforces.com/contest/1715/problem/D 思路&#xff1a;首先对于k某位为0的话&#xff0c;那么i和j这一位上一定是0&#xff0c;所以我们考虑用a数组记录确定下来的位&#xff0c;a数组0的意义代表一定为0&#xff0c;1的意义代表可能0可能1&#x…