今天在阅读一份第三方代码时,看到一个内存池初始化操作如下:
1 ven::MemPool* mp = new ven::MemPool; 2 mp->init({{ 8 * 1024,{ 1000, 100 } },}); 3 mpool = mp;
在init中直接传入了一个复杂{}包括起来的数据块,一开始以为这是std::initializer_list的用法,那么init的参数类型就是一个std::initializer_list了。
查看init定义如下:
void init(MemPoolConf conf = MemPoolConf());也就是说{}数据块是MemPoolConf构造函数的参数。
MemPoolConf的定义是:
typedef std::map<uint32_t, MemConf> MemPoolConf;是一个map,以一个整数为key,MemConf对象为value。
所以整个init就是对一个map进行值初始化。(C++新标准,见Primer5 page377)
MemConf定义是:
class MemConf {
public:
uint32_t init_cnt_ = 0;
uint32_t step_cnt_ = 0;
public:
MemConf(uint32_t init_cnt, uint32_t step_cnt)
: init_cnt_(init_cnt)
, step_cnt_(step_cnt)
{}
};
也就是说MemConf有两个整数成员。这么跟踪下来的话,对于{}数据块的取值过程就比较明朗了。
上面提到的map容器MemPoolConf,其key是8*1024即8192。value是{1000,100},传给MemConf的构造函数,init_cnt_cnt =1000,step_cnt_=100;
代码实际跟踪下来也的确如此。
当然{}数据块的写法,的确很容易让人误解。
{{ 8 * 1024,{ 1000, 100 } },}
最外面红色大括号表示里边放的是map的元素,第二个逗号后无内容,表示此map大小为1.那么此{}数据块等价写法是
{ 8 * 1024,{ 1000, 100 } } 这样就看的清晰了。
此例说明即便碰到复杂的数据块,碰到C++这样的强类型语言,结合参数类型定义,一步步拆解,总会水落石出。
一开始列的代码里第三行是个指针赋值操作。指针间的赋值是地址的赋值,此后两个指针都指向同一个地址,也就是两个指针所指向的内容相同。
此时要注意的是如果指针是new出来的, 那么最终的delete,只能删除其中一个,不能两个都delete,否则程序会崩溃。