个人笔记,持续更新,如果有遇到相同的疑问希望可以帮助大家。
Allocator
P45
问题1:
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
调用系统全局operator new函数来申请一个内存空间,传入参数为size_t类型,使用了一个强制类型转换,函数返回void类型指针,再使用强制类型转换为T,赋给tmp指针,指向申请的内存空间。
https://www.cnblogs.com/raichen/p/5808766.html
C++ new操作包括两个步骤:(1)调用::operator new 配置内存;(2)调用构造函数构造对象内容。
问题2:
template <class T1, class T2>
inline void _construct(T1* p, const T2& value){
new(p) T1(value);
}
placement new操作,需要包含new.h头文件,就是在定向new一个对象。使用new在p指针指向的内存空间生成一个T1类型的对象,利用T2类型的对象value来进行初始化。
https://blog.csdn.net/u014209688/article/details/90047713
P51
问题1:
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*){
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
traits编程技巧,对于默认数据类型(int, long, double, float…),其析构由编译器自行完成,因此对其进行显式析构是无意义的(trivial),即判断其存在trivial destructor, 所以对其不作任何处理,否则显式析构。
https://blog.csdn.net/pililipalalar/article/details/53446918
在2.3节内存基本处理工具部分也采用了同样的编程技巧。
P57
问题1:
static void (* set_malloc_handler(void (*f)()))()
{
void (* old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
函数名搞得十分复杂,对于我这种初学者十分不友好,查阅了相关资料发现应该从里往外读。
void (*f)()
指一个void(*)()类型的函数指针f
set_malloc_handler(void (*f)())
set_malloc_handler接受一个void(*)类型的函数指针参数。
static void (* set_malloc_handler(void (*f)()))()
定义了一个函数set_malloc_handler,它接受一个void ()()类型的参数f,返回类型为void ()()。
这里需要区分函数指针和返回类型为指针的函数:
// 函数指针
int (*p)(int, int){}
// 函数的返回类型为指针
int* p(int, int){}
https://www.cnblogs.com/Chierush/p/3745520.html
https://blog.csdn.net/charles1e/article/details/51620673
知识点:
函数指针
P58
问题1:
/**
* 初始值为0,由用户指定内存不足时的处理函数
*/
template<int inst>
void (*_malloc_alloc_template<int inst>::_malloc_alloc_oom_handler)() = 0;
template<int inst>
void *_malloc_alloc_template<int inst>::oom_malloc(size_t n){
void (*my_malloc_handler)();
void *result;
for(;;){
my_malloc_handler = _malloc_alloc_oom_handler;
if(0 == my_malloc_handler){
_THROW_BAD_ALLOC;
}
//调用处理函数,企图释放其他内存
(*my_malloc_handler)();
//再次尝试配置内存
result = malloc(n);
if(result){
return result;
}
}
}
如果不太明白函数指针,可以理解一下这个地方的代码含义:__malloc_alloc_oom_handler函数由客端自己设定,如果默认则为0。在函数体中,首先将__malloc_alloc_oom_handler函数赋给函数指针my_malloc_handler(代表后者可以直接调用前面的函数),如果其为0,则说明客端没有设定处理函数,直接抛出异常,否则调用处理函数,再重新尝试配置内存,直至成功。
P60
知识点:
结构体和联合的内存对齐
问题1:
union obj{
union obj* free_list_link;
char client_data[1];
};
结合union的特点,这里可以看做一物二用。看第一字段,obj视为一个指针,指向同类型的下一个obj指针,看第二字段,obj视为一个指针,指向实际区块。
P61
知识点:
枚举
P62
知识点:
volatile关键字:随时可能更改的变量
P68
知识点:
内存池(Memory Pool):
template <bool __threads, int __inst>
char*
__default_alloc_template<__threads,__inst>::_S_chunk_alloc(size_t __size,
int&__nobjs)
{
char* __result;
size_t __total_bytes = __size * __nobjs;
size_t __bytes_left = _S_end_free - _S_start_free; // 内存池剩余空间
if (__bytes_left >= __total_bytes) { // 内存池剩余空间完全满足需求
__result= _S_start_free;
_S_start_free+= __total_bytes;
return(__result);
} else if (__bytes_left >= __size) { // 内存池剩余空间不能完全满足需求,但足够供应一个(含)以上的区块
__nobjs= (int)(__bytes_left/__size);
__total_bytes= __size * __nobjs;
__result= _S_start_free;
_S_start_free+= __total_bytes;
return(__result);
} else { // 内存池剩余空间连一个区块的大小都无法提供
size_t __bytes_to_get =
2 *__total_bytes + _S_round_up(_S_heap_size >> 4);
//Try to make use of the left-over piece.
//把内存池当前剩下的一些小残余零头利用一下。
if (__bytes_left > 0) {
_Obj*__STL_VOLATILE* __my_free_list =
_S_free_list+ _S_freelist_index(__bytes_left);
((_Obj*)_S_start_free)-> _M_free_list_link = *__my_free_list;
*__my_free_list= (_Obj*)_S_start_free;
}
_S_start_free= (char*)malloc(__bytes_to_get);
if (0 == _S_start_free) {
size_t __i;
_Obj*__STL_VOLATILE* __my_free_list;
_Obj*__p;
//Try to make do with what we have. That can't
//hurt. We do not try smaller requests, since that tends
//to result in disaster on multi-process machines.
for (__i = __size;
__i<= (size_t) _MAX_BYTES;
__i+= (size_t) _ALIGN) {
__my_free_list= _S_free_list + _S_freelist_index(__i);
__p= *__my_free_list;
if (0 != __p) {
*__my_free_list= __p -> _M_free_list_link;
_S_start_free= (char*)__p;
_S_end_free= _S_start_free + __i;
return(_S_chunk_alloc(__size,__nobjs));
//Any leftover piece will eventually make it to the
//right free list.
}
}
_S_end_free= 0; // In case of exception.
_S_start_free= (char*)malloc_alloc::allocate(__bytes_to_get);
//This should either throw an
//exception or remedy the situation. Thus we assume it
//succeeded.
}
_S_heap_size+= __bytes_to_get;
_S_end_free= _S_start_free + __bytes_to_get;
return(_S_chunk_alloc(__size,__nobjs));
}
}
chunk_alloc()函数以end_free - start_free来判断内存池的水量。如果水量充足,则直接调出20个区块;不足但能提供1个以上区块则拨出这不足的20个区块,如果1个区块都拨不出去,则利用malloc从heap中申请内存,为内存池注入活水源头以应付需求,新水量为需求量的两倍,再加上一个随配置次数增加而愈来愈大的附加量。
Iterators
P81
知识点:
explicit关键字:阻止隐式转换
智能指针
P101
traits编程技法