Chapter 29.优化内存分配

 简介

C++中,内存分配和对象构造是一起的(new所做的工作就是为特定类型分配内存,并在新分配的内存中构造该类型的一个对象 ),但我们有时想自己管理内存分配、对象构造,即把内存分配和对象构造分离开来

eg:

如stl中vector会预分配一定额外内存,但不进行构造,因为对没有使用的内存构造对象是很浪费的,可能用永远不使用这部分额外的内存,所以内存分配和对象构造有时就需要分离开来

allocator类模板简介

在vs2010中allocator类模板和uninitialized_copy/fill/fill_n都包含在#include <memory>头文件中

allocator<T> a;//这个还明显就是定义一个a的allocator<T>的对象,用来分配原始内存、构造T类型的对象

a.allocate(n);//分配原始内存以保存n个T类型的对象

a.construct(p,t);//在名为p的T*指针处构造一个T类型对象t,使用的是复制构造函数

a.destroy(p);//对名为p的T*指针所指对象析构

a.deallocate(p,n);//在名为p的T*指针处释放n个T类型对象的内存

uninitialized_copy/fill/fill_n简介

uninitialized_copy(b,e,b2);//把b-e这个输入范围的元素复制到b2开始的原始内存中,此算法作用是在目的地构造元素,而不是赋值

uninitialized_fill(b,e,t);//把b-e这个范围的对象初始化为t的副本

uninitialized_fill_n(b,e,t,n);//把b-e这个范围至多n个对象初始化为t的副本

分配和释放未构造的原始内存的方法

1.allocator类中的a.allocate(n)、a.deallocate(p,n)两个方法

2.operator new 和 operator delete两个标准库函数

两个方法的区别:allocator类中方法是对类型化指针的操作,而operator new/delete是对void*指针的操作

原型:

void *operator new(size_t);

void *operator new[](size_t);

void *operator delete(void*);

void *operator delete[](void*);

eg://new和delete表达式工作流程
string *sp=new string("hello");
1.调用operator new分配原始内存
2.运行string类模板的构造函数构造对象
3.返回指针向新分配并构造对象的指针
delete sp;
1.析构
2.调用operator delete释放内存

原始内存中构造和析构对象的方法

1.allocator类中的a.construct(p,t)、a.destroy(p)两个方法

2.定位new表达式,使用可以是任何构造函数,并直接建立对象

3.直接调用对象的析构函数撤销对象

4.算法uninitialized_fill和uninitialized_copy就像fill、copy算法一样构造对象

定位new表达式的作用

在特定的、预分配的内存地址(原始内存,未构造)构造一个对象

格式:

new (place_address) type;

new (place_address) type(initializer-list);

//place_address是一个指针,initializer-list是一个初始化列表

eg:
//与alloc.construct(p,t)的区别
allocator<string> alloc;
string *sp=alloc.allocate(2);//分配两个strings原始内存
new (sp) string(b,e);//直接构造
alloc.construct(sp+1,string(b,e));//使用复制构造函数

eg://Vector.h
#ifndef __VECTOR_ALLOC_H__
#define __VECTOR_ALLOC_H__


/*
 *
 *	function:	A very simple vector template class and incompletely and many bugs but I have no time to fix them
 *	author:		vv_VV_vv
 *	time:		2012-12-20 14:06:36
 */
#include <memory>
#include <cstddef>
#include <limits>
#include <exception>

template <class T>
class Vector
{
public:
	typedef T* iterator;
	Vector():elements(0),first_free(0),m_end(0){}
	void push_back(const T &t);
	void pop_back();
	T& operator[](std::size_t N)
	{
		return elements[N];
	}
	const T& operator[](std::size_t N) const
	{
		return elements[N];
	}
	std::size_t size() const
	{
		return first_free-elements;
	}
	std::size_t capacity() const
	{
		return m_end-elements;
	}
	void reserve(std::size_t N)
	{
		if (std::numeric_limits<std::size_t>::max()<N)
		{
			throw std::out_of_range("reserve too long!");
		}
		else if (capacity()<N)//重新分配
		{
			//记录vector.size()
			std::ptrdiff_t size=first_free-elements;
			//给出新vector.capacity()大小,大小为原来vector.size()的两倍
			std::ptrdiff_t newCapacity=N;

			//分配新内存,大小为newCapacity()
			T *newElements=alloc.allocate(newCapacity);
			//复制原数据,把elements到first_free,复制到newElements指针处
			std::uninitialized_copy(elements,first_free,newElements);
			//析构原数据,从后到前依次析构
			for (T *p=first_free; p != elements;)
			{
				alloc.destroy(--p);
			}
			//释放原数据,头指针为elements,大小为从m_end-elements
			if (elements)
			{
				alloc.deallocate(elements,m_end-elements);
			}
			//重新赋值elements first_free m_end
			elements=newElements;
			first_free=elements+size;
			m_end=elements+newCapacity;
		}
	}
	void resize(size_t N)
	{
		if (N<size())
		{
			for (T *p=elements; p != elements+N; ++p)
			{
				alloc.destroy(p);
			}
			first_free=elements+N;
		}
		else if (size()<N)
		{
			reserve(N-size());
			std::uninitialized_fill_n(m_end,N-size(),T(0));
			m_end+=N+size();
		}
	}
	void clear()
	{
		if (!empty())
		{
			for (T *p=first_free; p != elements;)
			{
				alloc.destroy(--p);
			}
			if (elements)
			{
				alloc.deallocate(elements,m_end-elements);
			}
			elements=first_free=m_end=0;
		}
	}
	bool empty() const
	{
		return elements==first_free;
	}
	iterator begin() const
	{
		return elements;
	}
	iterator end() const
	{
		return first_free;
	}
	friend bool operator==(const Vector<T> &lhs,const Vector<T> &rhs);
	friend bool operator!=(const Vector<T> &lhs,const Vector<T> &rhs);
	//operator* and const version
	T& operator*()
	{
		return *first_free;
	}
	const T& operator*() const
	{
		return *first_free;
	}
	T& operator++()//prefix ++
	{
		if (first_free==m_end)
		{
			throw std::out_of_range("++m_end() is forbidden!");
		}
		++first_free;
		return *this;
	}
	T& operator++(int)//postfix ++
	{
		T ret(*this);
		++*this;
		return ret;
	}
	T& operator--()//prefix --
	{
		if (elements<first_free)
		{
			throw std::out_of_range("--beg() is forbidden!");
		}
		--first_free;
		return *this;
	}
	T& operator--(int)//postfix --
	{
		T ret(*this);
		--*this;
		return ret;
	}
private:
	//declare
	static std::allocator<T> alloc;
	void reallocate();
	T *elements;	//first one
	T *first_free;	//last of the m_end
	T *m_end;			//capacity m_end
	/*
			0              5  6         
			|--1--2--3--4--|--|------------|
		    elemnts		      first_free   m_end
	*/
};


//define
template <class T> 
std::allocator<T> Vector<T>::alloc;

template <class T>
void Vector<T>::push_back(const T &t)
{
	if (first_free==m_end)
	{
		reallocate();
	}
	alloc.construct(first_free,t);//same as placement new : new (first_free) T(t);
	++first_free;
}

template <class T>
void Vector<T>::pop_back()
{
	if (empty())
	{
		throw std::logic_error("vector is empty!");
	}
	alloc.destroy(first_free);
	--first_free;
}

//整体思路
/*
	1.新数据大小,newCapacity=2*std::max(size,1)
	2.分配新数据内存,alloc.allocate(newCapacity)
	3.复制原数据,std::uninitialized_copy(原数据elements,原数据first_free,新数据newElements)
	4.析构原数据,alloc.destroy(pointer)
	5.释放原数据,alloc.deallocate()
	6.重新整理指针
*/
template <class T>
void Vector<T>::reallocate()
{
	//记录vector.size()
	std::ptrdiff_t size=first_free-elements;
	//给出新vector.capacity()大小,大小为原来vector.size()的两倍
	std::ptrdiff_t newCapacity=2*std::max(size,1);


	//分配新内存,大小为newCapacity()
	T *newElements=alloc.allocate(newCapacity);//same as : T *newElements=static_cast<T*>(operator new[](newCapacity*sizeof(T));
	//复制原数据,把elements到first_free,复制到newElements指针处
	std::uninitialized_copy(elements,first_free,newElements);
	//析构原数据,从后到前依次析构
	for (T *p=first_free; p != elements;)
	{
		alloc.destroy(--p);
	}
	//释放原数据,头指针为elements,大小为从m_end-elements
	if (elements)
	{
		alloc.deallocate(elements,m_end-elements);//same as : operator delete[] (elements);
	}
	//重新赋值elements first_free m_end
	elements=newElements;
	first_free=elements+size;
	m_end=elements+newCapacity;
}

template <class T>
bool operator!=(const Vector<T> &lhs,const Vector<T> &rhs)
{
	if (lhs.first_free!=rhs.first_free)
	{
		return true;
	}
	return false;
}

template <class T>
bool operator==(const Vector<T> &lhs,const Vector<T> &rhs)
{
	return !(lhs!=rhs);
}

#endif	//__VECTOR_ALLOC_H__
//main.cpp
#include "Vector.h"
#include <iostream>
using std::cin;	using std::cout;
using std::endl;

int main()
{
	Vector<int> vec;
	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);
	for (int i = 0; i != vec.size(); ++i)
	{
		cout<<vec[i]<<'\t';
	}
	cout<<endl;
	for (Vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	{
		cout<<*iter<<'\t';
	}
	vec.pop_back();
	cout<<endl;
	for (Vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	{
		cout<<*iter<<'\t';
	}
	vec.reserve(1);
	cout<<endl;
	for (Vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	{
		cout<<*iter<<'\t';
	}
	vec.resize(1);
	cout<<endl;
	for (Vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter)
	{
		cout<<*iter<<'\t';
	}

	char ch;
	cin>>ch;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值