C++中,在需要对象时使用new操作符,为对象分配内存并在分配的内存处初始化一个对象。
在使用new操作符时,有两步1、给对象分配内存,这时内存是未构造的2、在分配内存处运行构造函数。
在一些情况下,第2步是不需要的,或者可以推迟第2步的操作,先分配内存,在需要时,在预先分配的内存中再构造对象。例如,我们构建了一个对象,但是从来不使用,在使用时,已经给对象赋予了其他值。(在给没有对象的内存赋值时,其后果可能是灾难性的,之前在重载=运算符时就看以看到,赋值操作符是要删除左值的,如果没有左值,调用左值对象的析构函数程序崩溃)
delete操作符也是有2步,1、调用析构函数2、把对象所用内存还给系统。
在处理C++内存分配时,要解决2个问题。1、分配原始内存时,必须在内存中构造对象。2、在释放内存之前,必须适当地撤销对象。
C++提供2中方法来分配和释放未构造的原始内存。1、allocator类。2、operator new和operator delete。
C++也提供了不同的方法在原始内存中构造和撤销对象
1、allocator类的成员函数construct在未构造的内存中初始化对象,成员函数destroy在对象上运行析构函数。
2、定位new表达式,它接受之前未构造的内存的指针,在该内存中初始化对象或数组。
3、直接调用对象的构造、析构函数。运行析构函数并不是释放对象所占用内存,只是销毁对象。
4、算法uninitilalized_fill和uninitialized_copy
allocator类是一个类模板,它可以提供类型化内存分配和对象的构造与撤销
allocator<T> a;//a为allocator对象,处理T类型内存
a.allocate(n);//分配n*sizeof(T)大小的未构造的内存
a.deallocate(p,n);//释放内存n*sizeof(T),p为指向内存对象,并不运行析构函数
a.construct(p,t);//在指针p处构造对象,运行T类型的复制构造函数,用t初始化
a.destroy(p);//运行p指针处对象的析构函数
更多关于allocator的资料,参考这里:http://www.cplusplus.com/reference/memory/allocator/
这与操作符new和delete不同。operator new函数只是分配内存,operator delete只是销毁对象。
operator new函数有2个版本
void *operator new(size_t );//分配一个对象内存
void *operator new[](size_t);//分配一个数组内存
注意,上面函数返回的是void*指针,这个有点像malloc函数,在使用前要进行指针类型转换。
同理,operator delete函数也有2个版本
void *operator delete(void* );//释放对象
void *operator delete[](void *);//释放数组
有点像allocator的deallocate函数,但是delete函数是在void*指针上操作的。注意,operator delete函数并不运行析构函数,如果需要可以显示调用析构函数。
定位new表达式
定位new表达式是用来在已分配的内存上初始化对象的,它并不分配内存。使用方法如下:
new (p) type;//在指针p处构造type类型对象
new (p) type(initializer list);//在指针p处用初始化列表构造对象。
可以结合《STL源码剖析》”2.1-设计一个简单的空间配置器“来学习一下,使用operator new和operator delete以及定位new来实现allocator类。
#ifndef _JJALLOC_
#define _JJALLOC_
#include<new>
#include<cstddef>
#include<cstdlib>
#include<climits>
#include<iostream>
namespace JJ
{
template<class T>
inline T* _allocate(ptrdiff_t size, T*){//分配内存,但不初始化
std::set_new_handler(0);
T* tmp=(T*)(::operator new((size_t)(size*sizeof(T))));
if(tmp==0){
std::cerr<<"out of memory"<<std::endl;
exit(1);
}
return tmp;
}
template<class T>
inline void _deallocate(T* buffer){//释放内存
::operator delete(buffer);
}
template<class T1, class T2>
inline void _construct(T1* p, const T2& value){
new(p) T1(value);//定位new
}
template<class T>
inline void _destroy(T* ptr){
ptr->~T();//显示调用析构函数
}
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;
};
pointer allocate(size_type n, const void* hint=0)
{
return _allocate((difference_type)n, (pointer)0);
}
void deallocate(pointer p, size_type n)
{
_deallocate(p);
}
void construct(pointer p, const T& value)
{
_construct(p,value);
}
void destroy(pointer p)
{
_destroy(p);
}
pointer address(reference x)
{
return (pointer)&x;
}
const_pointer const_address(const_reference x)
{
return (const_pointer)&x;
}
size_type max_size()const
{
return size_type(INT_MAX*2/sizeof(T));//使用UNIT_MAX时编译出错
}
};
}
#endif