简介
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*);
原始内存中构造和析构对象的方法
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;
}