第十四章是国际化议题,解决不同地区因为文化差异,产生的输入与输出问题。这对于我暂时没有用,而且还有更好的第三方库可以解决这个问题。
(1)怎么使用配置器
配置器是容器的内存管理工具,实际的内存分配、初始化、销毁、回收工作由他干。
C++的配置器继承自allocator类,这是个模板类可以自己设置内存元素大小,所以我们不用关心到底要分配多少字节。
代码 | 效果 |
a.allocate(num) | 为num个元素分配内存 |
a.construct(p) | 初始化指针p的指向元素 |
destroy(p) | 销毁p所指的元素 |
deallocate(p,num) | 回收从p开始的num个元素空间 |
下面我们来看看vector的一个内部初始化函数的实现代码:
template <class T, class Allocator>
vector<T,Allocator>::vector(size_type num, const T&val, const Allocator& a) :alloc(a)
{
sizeElems =numElems = num;//这两个是类变量
elems =alloc.allocate(num);//这个是类变量
for(size_type i= 0; i < num; ++i)
{
alloc.construct(&elems[i], val);//用val初始化
}
}
这个for循环效率不行,针对没有初始化的内存空间,所以C++提供了另外一些初始化函数:
代码 | 效果 |
uninitialize_fill(beg, end, val) | 用val初始化beg-end |
uninitialize_fill_n(beg, num, val) | 用val初始化beg以及之后num个元素 |
uninitialize_copy(beg, end, mem) | 把beg-end复制到mem开头的空间 |
其中uninitialized_fill_n的代码实现如下,其他原理相同。
template< class ForwardIt, class Size,class T >
void uninitialized_fill_n(ForwardIt beg,Size num
const T& value)
{
typedef typename std::iterator_traits<ForwardIt>::value_typeValue;
ForwardIt save(beg);
try{
for (; num--; ++beg) {
::new (static_cast<void*>(&*beg)) Value(value);
}
}
catch(...)
{
for(; save!=beg; ++save)
{
save->~Value();
throw;
}
}
}
使用的是placementnew操作。加入了异常安全。
这样我的代码很漂亮了。
template <class T, class Allocator>
vector<T,Allocator>::vector(size_type num, const T&val, const Allocator& a) :alloc(a)
{
sizeElems =numElems = num;//这两个是类变量
elems =alloc.allocate(num);//这个是类变量
uninitialize_fill_n(elems,num, val);
}
然后是reserve的实现:
template <class T, class Allocator>
void vector<T,Allocator>::reserve(size_type size)
{
if (size <sizeElems)
return;
T* newElems =alloc.allocate(size);
unintialized_copy(elems,elems + numElems, newElem);//把原来的拷贝过来
for (size_type i= 0; i < numElems; ++i)
{
alloc.destroy(&elems[i]);
}
alloc.deallocate(elems,sizeElems);
sizeElems =size;
elems =newElems;
}
C++中提供了未初始化空间迭代器raw_storage_iterator,这样复制构造函数可以把上面的unintialized_copy,替换成更牛逼的代码:
template <class T, class Allocator>
vector<T, Allocator>::vector( constvector<T,>&val, const Allocator& a) : alloc(a)
{
sizeElems =numElems = val.size();//这两个是类变量
elems =alloc.allocate(numElems);//这个是类变量
......///主要是把原来的删除
copy(val.begin(),val.end(), raw_storage_iterator<T*, T>(elems));
}
(2)自定义配置器
现在关注一下怎么自定义配置器,下面是模板,以后照着改就行了。最关键的是怎么编写allocate(), deallocate()函数,这样可以实现内存优化分配。
template<class T>class allocator{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template<class U>
struct rebind
{
typedef allocator<U>other;
};
allocator() throw(){}
template<class U>
allocator(const allocator<U>&) throw(){}
~allocator() throw(){}
pointer allocate(size_typen,const void * hint=0)
{
return (pointer)(::operator new(num * sizeof(T)));//global new
}
void deallocate(pointer p,size_type n)
{
::operator delete ((void*)p);//global delete
}
void construct(pointer p,const T& value)
{
new( (void*)p) T(value);//placementnew operator
}
void destroy(pointer p){p->~T();}//
pointer address(reference x){return (pointer)&x;}
const_pointer const address(const_referencex)
{
return (const_pointer)&x;
}
size_type max_size() const{
return size_type(numeric_limits<size_t>::max()/sizeof(T));
}
};
}//end