new和operator new
new是关键字,new 操作符的执行过程:
- 调用operator new分配内存;
- 调用构造函数在operator new返回的内存地址处生成类对象;
operator new是一个函数,可以被重载,通过重载它,可以改变new操作符的功能。功能类似malloc,如果类中没有重载operator new,那么调用的就是全局的::operator new来从堆中分配内存。
new将内存分配和对象构造组合在一起。
一般情况下,将内存分配和对象构造组合在一起会导致不必要的浪费。可能创建了一些永远不会用到的对象,或者使用到的元素被重复赋值两次。
allocator类帮助我们将内存分配和对象构造分离,可以分配大量内存,只有在真正需要的时候才执行对象创建操作。
类模板allocator
继承自__allocator_base,只定义了构造和析构函数。
template<typename _Tp>class allocator: public __allocator_base<_Tp>{public:typedef size_t size_type;typedef ptrdiff_t difference_type;typedef _Tp* pointer;typedef const _Tp* const_pointer;typedef _Tp& reference;typedef const _Tp& const_reference;typedef _Tp value_type;template<typename _Tp1>struct rebind{ typedef allocator<_Tp1> other; };#if __cplusplus >= 201103L// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2103. std::allocator propagate_on_container_move_assignmenttypedef true_type propagate_on_container_move_assignment;typedef true_type is_always_equal;
#endifallocator() throw() { }allocator(const allocator& __a) throw()//throw()表示该函数不会抛出异常: __allocator_base<_Tp>(__a) { }template<typename _Tp1>allocator(const allocator<_Tp1>&) throw() { }~allocator() throw() { }// Inherit everything else.};
__allocator_base是__gnu_cxx::new_allocator<_Tp>别名
template<typename _Tp>using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
类模板new_allocator
除了析构函数和构造函数之外,还定义了allocate、deallocate分配和释放内存、construct、destroy构造和析构对象。
template<typename _Tp>class new_allocator{public:typedef size_t size_type;typedef ptrdiff_t difference_type;typedef _Tp* pointer;typedef const _Tp* const_pointer;typedef _Tp& reference;typedef const _Tp& const_reference;typedef _Tp value_type;template<typename _Tp1>struct rebind{ typedef new_allocator<_Tp1> other; };#if __cplusplus >= 201103L// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2103. propagate_on_container_move_assignmenttypedef std::true_type propagate_on_container_move_assignment;
#endifnew_allocator() _GLIBCXX_USE_NOEXCEPT { }new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }template<typename _Tp1>new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }~new_allocator() _GLIBCXX_USE_NOEXCEPT { }pointer address(reference __x) const _GLIBCXX_NOEXCEPT{ return std::__addressof(__x); }const_pointer address(const_reference __x) const _GLIBCXX_NOEXCEPT{ return std::__addressof(__x); }// NB: __n is permitted to be 0. The C++ standard says nothing// about what the return value is when __n == 0.pointer allocate(size_type __n, const void* = static_cast<const void*>(0)){if (__n > this->max_size())std::__throw_bad_alloc();return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));}// __p is not permitted to be a null pointer.void deallocate(pointer __p, size_type){::operator delete(__p);}size_type max_size() const _GLIBCXX_USE_NOEXCEPT{ return size_t(-1) / sizeof(_Tp); }template<typename _Up, typename... _Args>void construct(_Up* __p, _Args&&... __args){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }template<typename _Up>void destroy(_Up* __p) { __p->~_Up(); }};
可以看到,在allocate和deallocate中分别调用了::operator new和::operator delete,实现分配和释放内存。::运算符被称为作用域解析运算符,通过加上这个前缀,告诉编译器在全局命名空间中查找该类型。
pointer allocate(size_type __n, const void* = static_cast<const void*>(0))
{if (__n > this->max_size())std::__throw_bad_alloc();return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
// __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type)
{::operator delete(__p);
}
在construct()调用了构造函数,使用placement new在指定内存中构建对象(定位new允许我们在一个特定的、预先分配的内存地址上构造对象,placement new是一种特殊的operate new),并使用std::forward转发模板参数到构造函数。
template<typename _Up, typename... _Args>void construct(_Up* __p, _Args&&... __args){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
在destroy()中调用了析构函数。
template<typename _Up>void destroy(_Up* __p) { __p->~_Up(); }