服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++详细讲解内存管理工具primitives

C++详细讲解内存管理工具primitives

2023-02-14 15:42温逗死 C/C++

文章向大家介绍C++内存管理primitives,主要包括primitives使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下

primitives

C++详细讲解内存管理工具primitives

分配 释放 属于 是否可重载
malloc() free() C 不可
new delete C++表达式 不可
::operator new() ::operator delete() C++函数
allocator::allocate() allocator::deallocate() C++标准库 可自由设计搭配容器

 

new 和 delete

C/C++中的new和delete的实现过程

C++详细讲解内存管理工具primitives

operator new():第一个参数表示大小,第二个参数表示保证这个函数不抛出异常。

C++详细讲解内存管理工具primitives

注意:构造函数不能直接调用,而析构函数可以直接调用。

new[] 与 delete[] 要搭配使用,未搭配使用可能会内存泄漏,泄露的是指针所指向的地方。

析构的时候次序会逆反。

C++详细讲解内存管理工具primitives

对于 析构函数 没有意义,new[] 是否对应 delete[] 不重要,但是 当析构函数有意义时,必须对应。

 

placement new

placement new 允许我们将对象建构在一个已经分配的内存中。并且没有对应的placement delete。

C++详细讲解内存管理工具primitives

第一部分,本来是分配内存,现在已经分配好了,所以直接返回。

 

重载 operator new

::operator new 和::operator delete 全部可以重载,但是不推荐。类中 operator new 也可以重载,实现所需功能,这是最常用的。

class Foo{
public:
	void *operator new(size_t);
	void operator delete(void*,size_t);
	//....
};

注意,可以写出多个版本,前提是每一个版本的声明都必须有独特的参数列。(第一参数必须是size_t)只有new所调用的ctor 抛出异常,才会调用这些重载版的 operator delete()。

即使 operator delete() 未能一一对应operator new() 也不会出现任何报错。换句话说:放弃处理构造函数抛出的异常。

 

per-class allocator

一:

C++详细讲解内存管理工具primitives

想利用类内重载operator new去接管内存的分配,然后利用内存池的观念【即创建出一大段连续空间的内存,然后将其切割成一小段一小段】,将创建的元素对象放在内存池切分好的各分段小内存片中,这样避免了多次调用new而造成生成多个带有cookie的内存空间。通过内存池的观念,可以生成一大段只带有两个头尾cookie的内存空间,而该一大段内存空间又被切分成每一小段的内存空间,且其中的每一小段内存空间片都可以共享这一整体的cookie信息。

因为为了能将一大段内存空间切分成一小段一小段,然后通过单向链表的形式串接起来,所以必须多引入一个Screen* next指针。但这又会增加class Screen的大小【增加了4字节】。

二:第一个占用了一个指针,浪费空间

C++详细讲解内存管理工具primitives

这个版本通过union关键字来减少使用next而所占耗的内存!

注意:上面两个版本的operator delete操作都没有将内存空间回收还回给系统,而是仍然存在的。虽然operator delete操作没有将这些分配的内存空间释放掉,但其仍在控制中即仍可继续重新使用【只不过freeStore或headOfFreeList此时又重新跑回整个一大块内存空间的头端】,所以不算内存泄漏!

三:上面的版本不具有复用性

将分配特定尺寸区块的memory allocator包装成一个class allocator,这样每个allocator object都是个分配器,体内维护一个free lists,不同类(如下面的class Foo,class Goo等) 里面调用生成的各自allocator objects维护不同的free lists。

C++详细讲解内存管理工具primitives

由上知,class Foo或class Goo其operator new或operator delete最终调用的都是allocator object所维护的free list而进行操作的!

另外,class Foo或class Goo中,应注意到:

static allocator myAlloc,即myAlloc必须是个静态成员变量,且在类外定义(赋初值)。如果其不是静态成员变量时,则在构建class Foo类对象时,是没办法调用到myAlloc的。因为非静态成员变量只能通过对象调用【但此时Foo对象还没生成又如何调用!!】。而myAlloc又是用来生成Foo类对象的,所以得通过类名调用即应设置为static类型。

C++详细讲解内存管理工具primitives

而class allocator的如下:

class allocator{
private:
	struct obj{
		struct obj* next;
	};
public:
	static void* allocate(size_t);
	static void deallocate(void*, size_t);
private:
	obj* freeStore = nullptr;
	const int CHUNK = 5; // 标准库一般设置为20
};
void* allocator::allocate(size_t size){
	obj* p;
	if(!freeStore){
		// linked list为空,则申请一大块
		size_t chunk = CHUNK * size;
		freeStore = p =(obj*)malloc(chunk); // 这里直接调用malloc进行分配空间
		// 将分配的一大块切分成5小段,并串接起来
		for(int i = 0; i < (CHUNK - 1); ++i){
			p->next = (obj*)((char*)p + size);
			p = p->next;
			// 上面这两步相当于p->next = p + 1,
			// 只不过这里需要适应不同的类下的操作,因而设置成这种形式!!
		}
		p->next = nullptr; // 最后一小段的下一个位置指向空
	}
	p = freeStore;
	freeStore = freeStore->next;
	return p;
}
void allocator::deallocate(void* p, size_t){
	// 将要删除的*p的位置调整为free list的头端
	((obj*)p)->next = freeStore;
	freeStore = (obj*)p;
}

四、macro for static allocator(per-class allocator 4)

C++详细讲解内存管理工具primitives

由第三版本知,其黄色部分我们想将其定义为宏操作,进一步简化代码内容:

// DECLARE_POOL_ALLOC used in class definition
#define DECLARE_POOL_ALLOC()\
public:\
void* operator new(size_t size){
return myAlloc.cllocate(size);
}\
void operator delete(void* p){
myAlloc.deallocate(p, 0);
}\
protected:\
static allocator myAlloc;

// IMPLEMENT_POOL_ALLOC used in class implementation file
#define IMPLEMENT_POOL_ALLOC(class_name)\
allocator class_name::myAlloc;

使用实例如图所示:

C++详细讲解内存管理工具primitives

在类内进行宏声明,在类外进行宏定义【告诉编译器传入参数的class type】

 

New Handler

C++详细讲解内存管理工具primitives

C++详细讲解内存管理工具primitives

 

=default,=delete

一个是需要默认版本,另一个是这个函数我不要。

这两个函数不仅使用构造,同时适用于 operator new 和 operator delete。

C++详细讲解内存管理工具primitives

到此这篇关于C++详细讲解内存管理工具primitives的文章就介绍到这了,更多相关C++ primitives内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_43142509/article/details/125465186

延伸 · 阅读

精彩推荐
  • C/C++C++生成随机浮点数的示例代码

    C++生成随机浮点数的示例代码

    在C++11之前,我们通常采用rand函数来生成随机数,但rand函数对一些情况显得难以处理。本文将介绍如何利用C++生成随机浮点数,需要的可以参考一下...

    叫我小秦就好了5952022-11-09
  • C/C++opencv3/C++ PHash算法图像检索详解

    opencv3/C++ PHash算法图像检索详解

    今天小编就为大家分享一篇opencv3/C++ PHash算法图像检索详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    阿卡蒂奥11062021-08-08
  • C/C++C语言简明讲解快速排序的应用

    C语言简明讲解快速排序的应用

    快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面...

    Mi ronin4582022-12-07
  • C/C++C语言进阶输入输出重定向与fopen函数使用示例详解

    C语言进阶输入输出重定向与fopen函数使用示例详解

    这篇文章主要为大家介绍了C语言进阶输入输出重定向与fopen函数的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步...

    hxj711362022-09-22
  • C/C++使用C++绘制GDI位图的基本编写实例

    使用C++绘制GDI位图的基本编写实例

    这篇文章主要介绍了使用C++绘制GDI位图的基本编写实例,一般来说适用于Windwos下的C++的GUI编程,需要的朋友可以参考下...

    mig_davidli10232021-03-18
  • C/C++Qt编写显示密码强度的控件

    Qt编写显示密码强度的控件

    这篇文章主要为大家详细介绍了Qt编写显示密码强度的控件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    友善啊,朋友7782022-12-24
  • C/C++C++中进行txt文件读入和写入的方法示例

    C++中进行txt文件读入和写入的方法示例

    这篇文章主要给大家介绍了C++中进行txt文件读入和写入的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C++具有一定的参考学习价值,...

    Williamhzw7612021-08-02
  • C/C++用C语言实现简易通讯录

    用C语言实现简易通讯录

    这篇文章主要为大家详细介绍了用C语言实现简易通讯录,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Quinn09186872021-06-20