《STL源码剖析》问题总结

个人笔记,持续更新,如果有遇到相同的疑问希望可以帮助大家。

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
SGI ALLOC示意
在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编程技法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值