首页 > 其他分享 >19容器空间配置器allocator

19容器空间配置器allocator

时间:2024-01-20 23:35:46浏览次数:27  
标签:容器 last 19 rhs ._ first allocator size

容器空间配置器allocator

容器的空间配置器allocator应分开完成:

  • 内存开辟
  • 内存释放
  • 对象构造
  • 对象析构
#include<iostream>

using namespace std;

// 容器的空间配置器allocator做四件事情  内存开辟/内存释放  对象构造/对象析构
template<typename T>
struct Allocator
{
	T* allocate(size_t size) // 负责内存开辟
	{
		return (T*)malloc(sizeof(T) * size);
	}
	void deallocate(void* p) // 负责内存释放
	{
		free(p);
	}
	void construct(T* p, const T& val) // 负责对象构造
	{
		new (p) T(val); // 定位new,调用拷贝构造函数
	}
	void destroy(T* p) // 负责对象析构
	{
		p->~T();
	}
};

/*
容器底层内存开辟,内存释放,对象构造和析构,都通过allocator空间配置器来实现
*/
template<typename T, typename Alloc = Allocator<T>>
class vector
{
public:
	vector(int size = 10)
	{
		// 需要把内存开辟和对象构造分开处理
		// _first = new T[size];
		_first = _allocator.allocate(size);
		_last = _first;
		_end = _first + size;
		cout << "vector()" << endl;
	}
	~vector()
	{
		// 析构容器有效的元素,然后释放_first指针指向的堆内存
		// delete[] _first;
		for (T *p = _first; p != _last; ++p) // 把有效的对象析构从_first到_last
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first); // 释放内存
		_first = _end = _last = nullptr;
	}
	vector(const vector<T>& rhs)
	{
		int size = rhs._end - rhs._first;
		//_first = new T[size];
		_first = _allocator.allocate(size);
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
	}
	vector<T>& operator = (const vector<T>& rhs)
	{
		if (this == &rhs)
		{
			return *this;
		}

		//delete[] _first;
		for (T* p = _first; p != _last; ++p) // 把有效的对象析构从_first到_last
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);

		int size = rhs._end - rhs._first;
		//_first = new T[size];
		_first = _allocator.allocate(size);
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
		return *this;
	}
	void push_back(const T& val)
	{
		if (full())
			expand();
		//*_last++ = val;  _last指针指向的内存构造一个值为val的对象
		_allocator.construct(_last, val);
		_last++;
	}
	void pop_back()
	{
		if (empty())
			return;
		//--_last;   不仅要把_last指针--,还需要析构删除的元素
		--_last;
		_allocator.destroy(_last);
	}
	T back() const
	{
		return *(_last - 1);
	}
	bool full() const { return _last == _end; }
	bool empty() const { return _first == _last; }
	int size() const { return _last - _first; }
private:
	T* _first;
	T* _last;
	T* _end;
	Alloc _allocator;
	void expand()
	{
		int size = _end - _first;
		//T* ptmp = new T[2 * size];
		T* ptmp = _allocator.allocate(2 * size);
		for (int i = 0; i < size; i++)
		{
			_allocator.construct(ptmp + i, _first[i]);
			//ptmp[i] = _first[i];
		}
		//delete[] _first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);
		_first = ptmp;
		_last = _first + size;
		_end = _first + 2 * size;
	}
};

class Test
{
public:
	Test() { cout << "Test()" << endl; }
	~Test() { cout << "~Test()" << endl; }
	Test(const Test&) { cout << "Test(const Test&)" << endl; }
};

int main()
{
	//无alloctor的情况下,定义一个基于Test的容器vector,会自动构造默认长度个Test对象
	//析构vec的过程则为delete首对象元素的指针,而应为先析构容器有效对象元素,再释放_first申请的堆内存
	vector<Test> vec;
	Test t1, t2, t3;
	//无alloctor的情况下,push_back(t1)相当于在构造函数已经生成对象元素的情况下,重载=运算符来重新赋值
	//应在只开辟内存的情况下,使用拷贝构造添加元素
	vec.push_back(t1);
	vec.push_back(t1);
	vec.push_back(t1);
	//无alloctor的情况下,pop_back只是将_last指针回退,如果末尾元素有外部资源(如堆资源),则会在元素对象被=重载覆盖后无法被再次访问,造成永久内存泄露。
	//应及时释放对象元素的外部资源并析构元素对象
	vec.pop_back();
	vec.pop_back();
	vec.pop_back();
	return 0;
}

标签:容器,last,19,rhs,._,first,allocator,size
From: https://www.cnblogs.com/sio2zyh/p/17977351

相关文章

  • 将 .NET 8应用 以 dotnet publish 创建容器镜像并结合 Github Actions 部署到 Azure
    介绍.NET8无需DockerFile即可为.NET应用创建docker映像的新方法,我将使用dotnetpublish将.NET应用容器化,在本文中,我将分享我如何为.NET8的项目创建一个简单的ci/cd的经验。它包括2个主题:创建用于生成.NET应用并将其发布到Azure的GitHub工作流如何使用do......
  • 容器管理工具Containerd
    一、Containerd介绍1.前言早在2016年3月,Docker1.11的DockerEngine里就包含了containerd,而现在则是把containerd从DockerEngine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。和原先包含在DockerEngine里containerd相比,独......
  • 云计算-代码开发流水线及CCE容器集群使用案例
    总结自己在使用华为云商业CI/CD代码流水和CCE容器集群部署案例学无止尽啊新项目构建镜像使用华为codearts代码流水线,详细见官方文档https://support.huaweicloud.com/productdesc-devcloud/devcloud_pdtd_00000.html以部署report-service构建测试镜像为例dockerfile文件前端FRO......
  • 如何恢复已经删除的 docker 容器的数据
    前言使用docker自带的volume机制进行数据的持久化,docker会在宿主机的特定位置(/var/lib/docker/volumes)维护各个volumes,面对容器删除的问题,有如下几个结论:容器启动(dockerrun)时,即使没有显示的指定-v-mount参数,容器的相关数据已经被作为volumes持久化存储了,比如在/var/li......
  • 【2024潇湘夜雨】WIN11_Pro_23H2.22631.3078软件选装纯净版1.19
    【系统简介】=============================================================1.本次更新母盘来自WIN11_Pro_23H2.22631.3078。2.增加部分优化方案,手工精简部分较多。3.OS版本号为22631.3078。精简系统只是为部分用户安装,个别要求高的去MSDN下。4.集成《DrvCeo-2.15.0.5》网卡版、......
  • Spring IOC 容器加载过程详解
    在Spring框架中,IOC(InversionofControl)容器是核心的概念之一。IOC容器负责管理和装配各个组件,本文将详细介绍SpringIOC容器的加载过程,包括如何配置、初始化和装配Bean。1.什么是IOC容器IOC容器是Spring框架的一个关键组件,负责管理Java对象的生命周期、配置信息以及对象之间的......
  • CF1922
    A简单题。发现如果存在匹配点就yes。B简单题。发现\(2^x+2^y\leq2^z(x,y<z)\),所以必定要有两个同样的最大值,然后直接列,两个最大值\(qzh_{i-1}+C^n_2\),三个\(C^n_3\),注意判0。C简单题。注意到走最近一定不比跳劣,所以能走最近就走最近,否则跳。D发现只有部分可能被选到,......
  • 题解 P6226 [BalticOI 2019 Day1] 潜艇
    【洛谷博客】题解P6226[BalticOI2019Day1]潜艇题意很清楚,忽略。分析看到这种字符串题很容易想到直接广度优先搜索,复杂度\(O(rc4^m)\)。很显然承受不了,所以考虑DP。状态设计设\(f_{i,x,y}\)表示执行完前\(i\)个操作后位置\((x,y)\)能否作为终点。设命令字符......
  • 20240119方程图像研究
    事情起因:研究人员:csj、lqy、xzq、yjf方程图像研究要求:描点法画图(使用卡西欧),在\(x\)轴上任取值,对于给定\(x_0\),应在有限时间内求出所有对应的\(y\)。草图绘制(直接绘制):综合方程性质(如定义域、单调性、对称性),明确区间单调性及端点,利用对称性作图、或化归为已知方程并求出其......
  • CF1922B & C & D
    CF1922B分析注意到\(2^0+2^1<2^2\),因此若\(a_i\nea_j\nea_k\),这组数就是不合法的,所以题目转化为有多少对三元组\(i,j,k\)使得\(a_i,a_j,a_k\)中至少有两个数相等。考虑分类讨论。第一类,\(a_i,a_j,a_k\)中有两个数相等,不妨设\(a_i=a_j\),那么先开一个map维护所有\(a......