stl 常用容器内存结构(持续更新)
std::string
Release
struct string{
union Bxty{
char Buf[0x10];
char * Ptr;
};
Bxty bxty;
#ifdef _WIN64
unsigned __int64 Mysize;
unsigned __int64 Myres;
#else
unsigned int Mysize;
unsigned int Myres;
#endif
}
Mysize
字符串的长度
Myres
字符串所在内存的大小(容积)
bxty
当Mysize
小于0x10时,字符串放在Buf里,
当Mysize
大于0x10时,申请一块内存,将字符串存入,然后用Ptr指向这块内存
Debug
struct string{
std::string::Proxy * _Myproxy
union Bxty{
char Buf[0x10];
char * Ptr;
};
Bxty bxty;
#ifdef _WIN64
unsigned __int64 Mysize;
unsigned __int64 Myres;
#else
unsigned int Mysize;
unsigned int Myres;
#endif
}
std::vector<T>
Release
struct vector{
T * first;
T * last;
T * end;
}
vector内部维护了一个顺序表
first
指向 顺序表 的第一个元素的地址
last
指向 顺序表 的最后一个元素的下一个元素的地址
end
指向这个顺序表申请的内存的末尾地址
Debug
struct vector{
std::vector<T>::Proxy * _Myproxy
T * first;
T * last;
T * end;
}
struct std::vector<T>::Proxy{
std::vector<T> * vector;
std::vector<T>::iterator begin;
}
std::vector<T>::iterator{
std::vector<T>::Proxy * _Myproxy;
std::vector<T>::iterator * begin;
T * m_cur;
}
std::vector<T>::Proxy
和 vector
是互相注册的关系
std::shared_ptr<T *>
std::shared_ptr{
T * ptr;
std::_Ref_count<T,lamdaxxx> * Rep;
}
ptr
对象的指针
Rep
引用计数对象的指针
std::_Ref_count{
void * vtf;
int refCount;
int weak;
T * ptr;
}
vtf
虚表
refCount
引用计数
当引用计数为0,调用对象的析构函数,但是Rep
不一定会被销毁,因为可能有其它的weak_ptr没有析构
weak
这个标志很有意思,当refCount
为0时,weak
减1,当有weak_ptr指向Rep
时,weak
加1,当weak_ptr析构时,weak
减一,当weak
为0时,Rep
被销毁
也就是说当没有智能指针指向对象时,Rep
被销毁
ptr
对象的指针
std::list<T>
std::list<T>::node{
node * _Next;
node * _Prev;
T _Myval;
}
_Next
下一个结点
_Prev
上一个结点
_Myval
保存的值,由T
决定
template<class T>
class list{
node * _Myhead;
unsigned __int64 _Mysize;
}
_Myhead
list维护了一个双向循环列表,_Myhead
指向头结点
_Mysize
结点的个数
注意,list的头结点
_Myval
是没有值的
std::map
template<class FIRST,class SECOND>
class pair{
private:
FIRST first;
SECOND second;
};
template<class FIRST, class SECOND, class pr = pair<FIRST, SECOND>>
class map {
private:
class node {
public:
node* lChild;
node* father;
node* rChild;
byte isHeadNode;
byte isRootNode;
pr data;
};
node* head;
unsigned __int64 size;
};
size
map节点的数量
head
指向头节点的指针,头节点的data是没有数据的,并且也不计入size
,头节点的lChild
,father
,rChild
,全部指向根节点
lChild
指向该节点的左子节点,若无的话,则指向头节点
rChild
指向该节点的右子节点,若无的话,则指向头节点
father
指向该节点的父节点
isHeadNode
是否是头节点的标记
isRootNode
是否是根节点或头节点的标记
data
存储的数据,类型为pair
std::function<T>的内存结构
- 32位
union std__Func_Storage
{
long double _Dummy1;
char _Dummy2[0x24];
void *_Ptrs[10];
};
- 64位
union std__Func_Storage
{
long double _Dummy1;
char _Dummy2[0x38];
void * _Ptrs[8];
};
function是一个非常特殊的类,下面的是的成员
-
vftable
第一个成员是虚表,虚表的第三个虚函数为调用函数,当std::function包装的是lamda函数,调用函数就是目标lamda函数
虚表指针可能有符号,可以看出函数类型,下面给三个例子
- lamda
std::_Func_impl_no_alloc__main_::_2_::_lambda_1__int_int_::_vftable_ int (*)(int)
- 普通函数
std::_Func_impl_no_alloc<int (__cdecl *)(int),int,int>::`vftable' int (__cdecl *)(int)
- 成员函数
const std::_Func_impl_no_alloc<std::_Binder<std::_Unforced,void (stu::*)(int),stu *,std::_Ph<1> const &>,void,int>::`vftable' void (stu::*)(int)
-
中间部分
如果std::function初始化的是一个lamda,第二个成员就是lamda捕获的变量,这个成员的大小是不定的,捕获的变量总大小就是这个成员的大小
若std::function存放的是普通函数,第二个成员就是函数地址
若std::function存放的是成员函数,第二个成员就是函数地址,第四个成员是成员函数的this指针
-
pStorage
第三个成员是
_Ptrs
数组的最后一个元素,类型为Storage *
,指向本对象的起始地址