ISO C++基本类型和变量(转载)
基本类型和变量.
像其他高级语言一样,ISO C++除了像C一样,有自己的基本类型:字符型,整形,浮点型等,还提供了可用于自定义类型机制.所谓的C++ STL,正是这个机制定义了大量的类型和操作.
比如可变长的string,vector等.一般和C一样,也是为了兼容C,内置类型一般小写.
对于所谓内置类型不同,一般指位数不同而已,比如int 16(当然这个有争议,很多语言都是32位,所以C++又定义了一个long 32)和float(32位),当然也有不同的类型位数一样,比如刚才int 和 short都是16.
其实所有的这一切都是编译器想怎么解释就怎么解释(也有标准的约束).
像C语言一样,C++的字符用单引号,字符串用双引号,这点和pascal不同,pascal都用单引号,编译器自行解释.另外,和pascal不同的是,C++/C定义常量,也用特殊标识,比如字符串前加"L"代表unicode串,整形后加L表示long型,也就是32位的.
与C一样,都用"\"作转义字符.整形和字符型在一定范围兼容.
作用域:C++比C多了名字空间作用域,类作用域(其实C也有struct作用域).
头文件,C直接用.h结尾的文件,而现在的C++头文件一般都不带.h,比如 #include <string> #include <string.h>,前者定义有string类型,而后者则是一些char *处理函数.
C/C++都有特殊类型,引用(符号&), 引用其实就是一个变量的别名,仅此而已.像const变量一样,引用必须初始化. 如:int i; int &reint = i;正因为引用是别名,所以不能直接对其赋值,&reint = i;(error).
枚举类型:其实就是定义一些常量的集合.关键字enum mode {input,output,append};枚举类型都有默认的值,从第一个为0开始,后面依次加1,input = 0,output = 1,append =2.当然也可以给定其初始化值.enum mode {input = 1,output,append};
像C一样,关键字typedef可以定义复杂的类型.比如typedef void (Message_Process::*FN_Msg)(Message*); FN_Msg为函数指针类型,可以用其定义其他的变量,比如FN_Msg p = NULL;
与C不同的是,C++有class关键字.标准库通过他,定义大量的数据类型,比如string,istream,ostream等等.虽然class和struct差不多,但class机制更复杂,主要就是他定义了一组权限规则,private,protected,public.(记得类后面有;号啊)struct内部的成员都是public属性.
C++标准库(STL)
首先名字空间using namespace std; 当然也可以直接using std::cin;
现在我们来玩玩string这个东东.这个东东在pascal里也有,内存分配是 引用计数 +Length + ansichar*,在string里,在C++里只知道是一个常用对象,具体怎么分配的,网上好多垃圾也没有说清楚.只说什么copyonwrite乱七八糟之云乎.既然是类,那么就要遵循C++实例规则.C++没有pascal那么严格,pascal里只有明确的create才能创造对象,C++到处都暗藏杀机.很多隐式定义.
string定义(四种):
string s1;
string s2(s1);//定义并初始化
string s3("value");//常量初始化
string s4(n,'c');//相同字符常量初始化
运算符重载(+,=(赋值),==,!=,>,<等等)
成员函数size和empty判断长度.
string::size_type类型
template<class E, //定义模板类,泛型化
class T = char_traits<E>, //T,A也一个泛型实例的类
class A = allocator<T> > //泛型类
class basic_string {
public:
typedef T traits_type; //定义泛型类型
typedef A allocator_type;
typedef T::char_type char_type; //这里A和T只是一个类域而已
typedef A::size_type size_type;
typedef A::difference_type difference_type;
typedef A::pointer pointer;
typedef A::const_pointer const_pointer;
typedef A::reference reference;
typedef A::const_reference const_reference;
typedef A::value_type value_type;
typedef T0 iterator;
typedef T1 const_iterator;
typedef reverse_iterator<iterator, value_type,
reference, pointer, difference_type>
reverse_iterator;
typedef reverse_iterator<const_iterator, value_type,
const_reference, const_pointer, difference_type>
const_reverse_iterator;
static const size_type npos = -1;
//隐式构造函数 ,以下都是其构造函数
explicit basic_string(const A& al = A()); //string str;分配一空字符串
basic_string(const basic_string& rhs); //string str(s1);
basic_string(const basic_string& rhs, size_type pos, size_type n, //string s4(str,1,5);用另一个字符串的一节去构造
const A& al = A());
basic_string(const E *s, size_type n, const A& al = A()); //
basic_string(const E *s, const A& al = A());
basic_string(size_type n, E c, const A& al = A());
basic_string(const_iterator first, const_iterator last, //可以看出,共有7种构造函数
const A& al = A());
basic_string& operator=(const basic_string& rhs); //赋值运算符重载
basic_string& operator=(const E *s);
basic_string& operator=(E c); //三种赋值运算
iterator begin(); //实现了迭代器算法
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
const_reference at(size_type pos) const;
reference at(size_type pos);
const_reference operator[](size_type pos) const; //下标重载
reference operator[](size_type pos);
const E *c_str() const; //返回c格式的字符串函数
const E *data() const; //.
size_type length() const; //长度大小操作
size_type size() const;
size_type max_size() const;
void resize(size_type n, E c = E());
size_type capacity() const;
void reserve(size_type n = 0);
bool empty() const;
basic_string& operator+=(const basic_string& rhs); //+=重载
basic_string& operator+=(const E *s);
basic_string& operator+=(E c);
basic_string& append(const basic_string& str); //添加
basic_string& append(const basic_string& str,
size_type pos, size_type n);
basic_string& append(const E *s, size_type n);
basic_string& append(const E *s);
basic_string& append(size_type n, E c);
basic_string& append(const_iterator first, const_iterator last);
basic_string& assign(const basic_string& str); //赋值
basic_string& assign(const basic_string& str,
size_type pos, size_type n);
basic_string& assign(const E *s, size_type n);
basic_string& assign(const E *s);
basic_string& assign(size_type n, E c);
basic_string& assign(const_iterator first, const_iterator last);
basic_string& insert(size_type p0,
const basic_string& str);
basic_string& insert(size_type p0,
const basic_string& str, size_type pos, size_type n);
basic_string& insert(size_type p0,
const E *s, size_type n);
basic_string& insert(size_type p0, const E *s);
basic_string& insert(size_type p0, size_type n, E c);
iterator insert(iterator it, E c);
void insert(iterator it, size_type n, E c);
void insert(iterator it,
const_iterator first, const_iterator last);
basic_string& erase(size_type p0 = 0, size_type n = npos);
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
basic_string& replace(size_type p0, size_type n0,
const basic_string& str);
basic_string& replace(size_type p0, size_type n0,
const basic_string& str, size_type pos, size_type n);
basic_string& replace(size_type p0, size_type n0,
const E *s, size_type n);
basic_string& replace(size_type p0, size_type n0,
const E *s);
basic_string& replace(size_type p0, size_type n0,
size_type n, E c);
basic_string& replace(iterator first0, iterator last0,
const basic_string& str);
basic_string& replace(iterator first0, iterator last0,
const E *s, size_type n);
basic_string& replace(iterator first0, iterator last0,
const E *s);
basic_string& replace(iterator first0, iterator last0,
size_type n, E c);
basic_string& replace(iterator first0, iterator last0,
const_iterator first, const_iterator last);
size_type copy(E *s, size_type n, size_type pos = 0) const;
void swap(basic_string& str);
size_type find(const basic_string& str,
size_type pos = 0) const;
size_type find(const E *s, size_type pos, size_type n) const;
size_type find(const E *s, size_type pos = 0) const;
size_type find(E c, size_type pos = 0) const;
size_type rfind(const basic_string& str,
size_type pos = npos) const;
size_type rfind(const E *s, size_type pos,
size_type n = npos) const;
size_type rfind(const E *s, size_type pos = npos) const;
size_type rfind(E c, size_type pos = npos) const;
size_type find_first_of(const basic_string& str,
size_type pos = 0) const;
size_type find_first_of(const E *s, size_type pos,
size_type n) const;
size_type find_first_of(const E *s, size_type pos = 0) const;
size_type find_first_of(E c, size_type pos = 0) const;
size_type find_last_of(const basic_string& str,
size_type pos = npos) const;
size_type find_last_of(const E *s, size_type pos,
size_type n = npos) con/t;
size_type find_last_of(const E *s, size_type pos = npos) const;
size_type find_last_of(E c, size_type pos = npos) const;
size_type find_first_not_of(const basic_string& str,
size_type pos = 0) const;
size_type find_first_not_of(const E *s, size_type pos,
size_type n) const;
size_type find_first_not_of(const E *s, size_type pos = 0) const;
size_type find_first_not_of(E c, size_type pos = 0) const;
size_type find_last_not_of(const basic_string& str,
size_type pos = npos) const;
size_type find_last_not_of(const E *s, size_type pos,
size_type n) const;
size_type find_last_not_of(const E *s,
size_type pos = npos) const;
size_type find_last_not_of(E c, size_type pos = npos) const;
basic_string substr(size_type pos = 0, size_type n = npos) const;
int compare(const basic_string& str) const;
int compare(size_type p0, size_type n0,
const basic_string& str);
int compare(size_type p0, size_type n0,
const basic_string& str, size_type pos, size_type n);
int compare(const E *s) const;
int compare(size_type p0, size_type n0,
const E *s) const;
int compare(size_type p0, size_type n0,
const E *s, size_type pos) const;
A get_allocator() const;
protected:
A allocator;
};
iterator(迭代器)
他的存在主要是为了集合数据的安全访问.也是提供一些遍历的方法.
begin和end操作.返回一个iterator.
vector<int>::iterator iter = ivec.begin();//返回容器的第一个元素iterator.
iterator还重载了许多符号,比如*,-,+等,以实现简单快捷安全的访问元素.
*iter = 0;//对当前元素赋值.
这里值得一提的是,当容器的元素增加,删除,或交换,该容器的iterator将失效,得重新检索得到iterator.
template<class C, class T, class Dist = ptrdiff_t> //ptrdiff_t是一个run-time library定义的类型
struct iterator { //可以看iterator是一个没有任何操作的模板结构.
typedef C iterator_category;
typedef T value_type;
typedef Dist distance_type;
};
而真正的具体定义却也只是像下面这样一句话而已.
typedef _A::pointer iterator;
typedef _A::const_pointer const_iterator;
//下面是他的具体实现
iterator begin()
{_Freeze();
return (_Ptr); }
const_iterator begin() const
{return (_Ptr); }
iterator end()
{_Freeze();
return ((iterator)_Psum(_Ptr, _Len)); }
const_iterator end() const
{return ((const_iterator)_Psum(_Ptr, _Len)); }
unsigned char& _Refcnt(const _E *_U) //字符串的引用,最大引用255次
{return (((unsigned char *)_U)[-1]); } //返回字符串内存中的前面一个字符
void _Freeze()
{if (_Ptr != 0
&& _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
_Grow(_Len);
if (_Ptr != 0)
_Refcnt(_Ptr) = _FROZEN; }
_E *_Ptr;//而_E此时是char,即指向string的首个字符
_E *_Ptr;
size_type _Len, _Res;
//真正的字符串只存储_Refcnt和char array[_Len]数组.
//从这上面可以看出,string对象内存只存储三个变量,第一个首字母指针,
//第二个是长度,第三个应该最大长度.因为string是一个可自动加长的类型.
可以看出,string的内存实现,很简单并且引用了_Refcnt机制,这个机制可以帮助我们实现copy_on_write.
但是可以明显看到,这点也给我们带来了麻烦.在多线程编程中,_Refcnt很容易被破坏,造成内存错误或者内存泄漏.
这点应该向pascal学习了,delphi的string增加了锁机制,所以可以很好在多线程使用.
struct char_traits<E> { //一个基本操作类模板,可以看出里面全部都是静态成员函数,
typedef E char_type; //所以只给其他类用,不实例对象
typedef T1 int_type;
typedef T2 pos_type;
typedef T3 off_type;
typedef T4 state_type;
static void assign(E& x, const E& y);
static E *assign(E *x, size_t n, const E& y);
static bool eq(const E& x, const E& y);
static bool lt(const E& x, const E& y);
static int compare(const E *x, const E *y, size_t n);
static size_t length(const E *x);
static E *copy(E *x, const E *y, size_t n);
static E *move(E *x, const E *y, size_t n);
static const E *find(const E *x, size_t n, const E& y);
static E to_char_type(const int_type& ch);
static int_type to_int_type(const E& c);
static bool eq_int_type(const int_type& ch1, const int_type& ch2);
static int_type eof();
static int_type not_eof(const int_type& ch);
};
以上可以看了,basic_string并没有重载一些常用的运算符,但实际我们又经常可以用到.比如 +,>,<,==等等
即没有像下面的
bool basic_string::operator<(const basic_string &rhs);
basic_string& basic_string::operator+(const basic_string &rhs);
等等,其实我猜测应该是编译器,把这些自行的解释了,比如<就用compare操作代替.当然我对C++没有什么深入研究的,只是猜测.
typedef basic_string<char> string;//这就是真正的string的全部,就一句话.表明它是操作char 的东东.
vector类型(不像string,而是一个类模板.)
同一类型对象的组合,像基本类型数组,我们称之为"容器".vector本身并不是直接类,也就是不能直接使用,在经过模板实例化.
vector也有好几种构造函数.
vector<T> v1; //构造空的vector对象.
vector<T> v2(v1); //将v1作副本构造一个vector对象.
vector<T> v3(n,i); //包含n个值为i的元素vector对象.
vector<T> v4(n); //包含n个值为初始化的元素的vector对象.
vector用引用对象初始化的时候,要保持兼容性.
template<class T, class A = allocator<T> >
class vector {
public:
typedef A allocator_type;
typedef A::size_type size_type;
typedef A::difference_type difference_type;
typedef A::reference reference;
typedef A::const_reference const_reference;
typedef A::value_type value_type;
typedef T0 iterator; //这里定义一个迭代器.
typedef T1 const_iterator;
typedef reverse_iterator<iterator, value_type,
reference, A::pointer, difference_type>
reverse_iterator;
typedef reverse_iterator<const_iterator, value_type,
const_reference, A::const_pointer, difference_type>
const_reverse_iterator;
//以下是vector的四个构造函数
explicit vector(const A& al = A());
explicit vector(size_type n, const T& v = T(), const A& al = A());
vector(const vector& x);
vector(const_iterator first, const_iterator last,
const A& al = A());
void reserve(size_type n);
size_type capacity() const;
iterator begin(); //实现了迭代器
const_iterator begin() const;
iterator end();
iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
void resize(size_type n, T x = T()); //一些基本操作
size_type size() const;
size_type max_size() const;
bool empty() const;
A get_allocator() const;
reference at(size_type pos);
const_reference at(size_type pos) const;
reference operator[](size_type pos); //下标操作
const_reference operator[](size_type pos);
reference front();
const_reference front() const;
reference back();
const_reference back() const;
void push_back(const T& x);
void pop_back();
void assign(const_iterator first, const_iterator last);
void assign(size_type n, const T& x = T());
iterator insert(iterator it, const T& x = T());
void insert(iterator it, size_type n, const T& x);
void insert(iterator it,
const_iterator first, const_iterator last);
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
void clear();
void swap(vector x);
protected:
A allocator; //包含一个对象分配器
};
template<class T>
class allocator { //对象分配器
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
pointer address(reference x) const; //地址及地址指针
const_pointer address(const_reference x) const;
allocator(); //构造函数
allocator<T>& operator=(const allocator<T>); //基本的赋值运算
pointer allocate(size_type n, const void *hint);
void deallocate(pointer p, size_type n); //释放对象
void construct(pointer p, const T& val); //构造内存对象
void destroy(pointer p); //释放指针
size_type max_size() const;
};
具体iterator实现
typedef _A::pointer _Tptr; //普通指针
typedef _A::const_pointer _Ctptr; //这时仅仅是一个常指针类型
typedef _A::reference reference;
typedef _A::const_reference const_reference;
typedef _A::value_type value_type;
typedef _Tptr iterator; //这就是vector的iterator的全部
typedef _Ctptr const_iterator; //vertor的const_iterator
iterator begin()
{return (_First); }
const_iterator begin() const
{return ((const_iterator)_First); }
iterator end()
{return (_Last); }
const_iterator end() const
{return ((const_iterator)_Last); }
_A allocator;
iterator _First, _Last, _End;
//从上面可以看vector只有四个成员元素,第一个对象分配器,接下来的三个,其实都是一个普通指针而已.
依次分析,其实所谓的iterator的*,+,-操作都是C++编译器的内置的指针操作而已.
另外上面的可以看出,上面的每个类都定义了好多const操作.其实const既可以定义变量,也可以定义类成员函数(此时放在类的成员函数后面).
当const修饰变量的时候,表明此变量不能修改.当const修改类成员函数,表明此函数不能修改类的成员元素.
上面只了解了几个常用的标准库,还有很多类似的库.
下面介绍下new和delete关键字.
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
int i;
string *psa = new string[3]; //这里下断点以跟踪
for (i=0;i<3;i++) {
psa[i] = "huzg";
}
for (i=0;i<3;i++) {
cout << psa[i] <<endl;
}
delete [] (psa); //这里调用了vector deleting destructor.
return 0;
}
9: string *psa = new string[3];
0040126D push 34h //这里其实是实际大小,34h=52
0040126F call operator new (00409840) //这里调用C++编译器内置函数operator new
00401274 add esp,4
operator new:
00409840 push ebp
00409841 mov ebp,esp
00409843 push ecx
00409844 push 1
00409846 mov eax,dword ptr [cb]
00409849 push eax
0040984A call _nh_malloc (0040a5a0)
0040984F add esp,8
00409852 mov dword ptr [res],eax
00409855 mov eax,dword ptr [res]
00409858 mov esp,ebp
0040985A pop ebp
0040985B ret
--- No source file -----------------------
0040985C int 3
0040985D int 3
0040985E int 3
0040985F int 3
//CRT内new的源码new.cpp
void * operator new( unsigned int cb )
{
void *res = _nh_malloc( cb, 1 );
return res;
}
//_nh_malloc又进入了DbgHeap.c文件里
void * __cdecl _nh_malloc (
size_t nSize,
int nhFlag
)
{
return _nh_malloc_dbg(nSize, nhFlag, _NORMAL_BLOCK, NULL, 0);
}
//此函数是__cdecl,和__stdcall一样都是从右到左压栈,但__cdecl栈是调用者来维护,也就是调用它函数清栈,__stdcall则是函数自己来维护.
void * __cdecl _nh_malloc_dbg (
size_t nSize, //34h
int nhFlag, //1
int nBlockUse, //1
const char * szFileName, //0
int nLine //0
)
{
void * pvBlk;
for (;;)
{
#ifdef _MT
/* lock the heap
*/
_mlock(_HEAP_LOCK);
__try {
#endif /* _MT */
/* do the allocation
*/
pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine);
#ifdef _MT
}
__finally {
/* unlock the heap
*/
_munlock(_HEAP_LOCK);
}
#endif /* _MT */
if (pvBlk || nhFlag == 0)
return pvBlk;
/* call installed new handler */
if (!_callnewh(nSize))
return NULL;
/* new handler was successful -- try to allocate again */
}
}
void * __cdecl _heap_alloc_dbg(
size_t nSize,
int nBlockUse,
const char * szFileName,
int nLine
)
{
long lRequest;
size_t blockSize;
int fIgnore = FALSE;
_CrtMemBlockHeader * pHead;
/* verify heap before allocation */
if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
_ASSERTE(_CrtCheckMemory());
lRequest = _lRequestCurr;
/* break into debugger at specific memory allocation */
if (lRequest == _crtBreakAlloc)
_CrtDbgBreak();
_CrtDefaultAllocHook:
00410E30 push ebp
00410E31 mov ebp,esp
00410E33 mov eax,1
00410E38 pop ebp
00410E39 ret
/* forced failure */
if (!(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, szFileName, nLine)) //这里进入系统给出的函数_CrtDefaultAllocHook:
{
if (szFileName)
_RPT2(_CRT_WARN, "Client hook allocation failure at file %hs line %d.\n",
szFileName, nLine);
else
_RPT0(_CRT_WARN, "Client hook allocation failure.\n");
return NULL;
}
/* cannot ignore CRT allocations */
if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK &&
!(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
fIgnore = TRUE;
/* Diagnostic memory allocation from this point on */
if (nSize > (size_t)_HEAP_MAXREQ ||
nSize + nNoMansLandSize + sizeof(_CrtMemBlockHeader) > (size_t)_HEAP_MAXREQ)
{
_RPT1(_CRT_ERROR, "Invalid allocation size: %u bytes.\n", nSize);
return NULL;
}
if (!_BLOCK_TYPE_IS_VALID(nBlockUse))
{
_RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n");
}
blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;
#ifndef WINHEAP
/* round requested size */
blockSize = _ROUND2(blockSize, _GRANULARITY);
#endif /* WINHEAP */
pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize); //进入_heap_alloc_base
if (pHead == NULL)
return NULL;
/* commit allocation */
++_lRequestCurr;
if (fIgnore)
{
pHead->pBlockHeaderNext = NULL;
pHead->pBlockHeaderPrev = NULL;
pHead->szFileName = NULL;
pHead->nLine = IGNORE_LINE;
pHead->nDataSize = nSize;
pHead->nBlockUse = _IGNORE_BLOCK;
pHead->lRequest = IGNORE_REQ;
}
else {
/* keep track of total amount of memory allocated */
_lTotalAlloc += nSize;
_lCurAlloc += nSize;
if (_lCurAlloc > _lMaxAlloc)
_lMaxAlloc = _lCurAlloc;
if (_pFirstBlock)
_pFirstBlock->pBlockHeaderPrev = pHead;
else
_pLastBlock = pHead;
pHead->pBlockHeaderNext = _pFirstBlock;
pHead->pBlockHeaderPrev = NULL;
pHead->szFileName = (char *)szFileName;
pHead->nLine = nLine;
pHead->nDataSize = nSize;
pHead->nBlockUse = nBlockUse;
pHead->lRequest = lRequest;
/* link blocks together */
_pFirstBlock = pHead;
}
/* fill in gap before and after real block */
memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);
/* fill data with silly value (but non-zero) */
memset((void *)pbData(pHead), _bCleanLandFill, nSize);
return (void *)pbData(pHead);
}
//进入malloc.c的_heap_alloc_base
void * __cdecl _heap_alloc_base (size_t size)
{
#ifdef WINHEAP
void * pvReturn;
#else /* WINHEAP */
_PBLKDESC pdesc;
_PBLKDESC pdesc2;
#endif /* WINHEAP */
#ifdef WINHEAP
if ( __active_heap == __V6_HEAP )
{
if ( size <= __sbh_threshold )
{
#ifdef _MT
_mlock( _HEAP_LOCK );
__try {
#endif /* _MT */
pvReturn = __sbh_alloc_block(size);
#ifdef _MT
}
__finally {
_munlock( _HEAP_LOCK );
}
#endif /* _MT */
if (pvReturn)
return pvReturn;
}
}
else if ( __active_heap == __V5_HEAP )
{
/* round up to the nearest paragraph */
if ( size )
size = (size + _OLD_PARASIZE - 1) & ~(_OLD_PARASIZE - 1);
else
size = _OLD_PARASIZE;
if ( size <= __old_sbh_threshold ) {
#ifdef _MT
_mlock(_HEAP_LOCK);
__try {
#endif /* _MT */
pvReturn = __old_sbh_alloc_block(size >> _OLD_PARASHIFT);
#ifdef _MT
}
__finally {
_munlock(_HEAP_LOCK);
}
#endif /* _MT */
if ( pvReturn != NULL )
return pvReturn;
}
return HeapAlloc( _crtheap, 0, size );//最终走到这里,直接调用ntdll里的HeapAlloc函数,没有内核符号,不能再跟踪了.
}
if (size == 0)
size = 1;
size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
return HeapAlloc(_crtheap, 0, size);
}
#else /* WINHEAP */
/* try to find a big enough free block
*/
if ( (pdesc = _heap_search(size)) == NULL )
{
if ( _heap_grow(size) != -1 )
{
/* try finding a big enough free block again. the
* success of the call to _heap_grow should guarantee
* it, but...
*/
if ( (pdesc = _heap_search(size)) == NULL )
{
/* something unexpected, and very bad, has
* happened. abort!
*/
_heap_abort();
}
}
else
return NULL;
}
/* carve the block into two pieces (if necessary). the first piece
* shall be of the exact requested size, marked inuse and returned to
* the caller. the leftover piece is to be marked free.
*/
if ( _BLKSIZE(pdesc) != size ) {
/* split up the block and free the leftover piece back to
* the heap
*/
if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
_SET_FREE(pdesc2);
}
/* mark pdesc inuse
*/
_SET_INUSE(pdesc);
/* check proverdesc and reset, if necessary
*/
_heap_desc.proverdesc = pdesc->pnextdesc;
return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
}
delete[] psa;
//这里应该调用了basic_string析构函数,而basic_string析构函数只有一个:~basic_string(){_Tidy(true); }
具体调用如下:
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::`vector deleting destructor':
00401419 call `eh vector destructor iterator' (00409db0)
//最后再调用basic_string析构函数
58: ~basic_string()
59: {_Tidy(true); }
00401550 push ebp
00401551 mov ebp,esp
00401553 sub esp,44h
00401556 push ebx
00401557 push esi
00401558 push edi
00401559 push ecx
0040155A lea edi,[ebp-44h]
0040155D mov ecx,11h
00401562 mov eax,0CCCCCCCCh
00401567 rep stos dword ptr [edi]
00401569 pop ecx
0040156A mov dword ptr [ebp-4],ecx
0040156D push 1
0040156F mov ecx,dword ptr [ebp-4]
00401572 call @ILT+25(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy) (00
00401577 pop edi
00401578 pop esi
00401579 pop ebx
0040157A add esp,44h
0040157D cmp ebp,esp
0040157F call __chkesp (00409c80)
00401584 mov esp,ebp
00401586 pop ebp
00401587 ret
--- No source file ---------------------------------------------------------------------------------------------------------------------------------------
00401588 int 3
00401589 int 3
0040158A int 3
void _Tidy(bool _Built = false)
{if (!_Built || _Ptr == 0)
;
else if (_Refcnt(_Ptr) == 0 || _Refcnt(_Ptr) == _FROZEN) //当引用计数为0,或者已经达到了最大引用计数255
allocator.deallocate(_Ptr - 1, _Res + 2); //释放字符串
else
--_Refcnt(_Ptr); //引用计数减一,此时并没有释放.
_Ptr = 0, _Len = 0, _Res = 0; }//这时清空对象本身
void deallocate(void _FARQ *_P, size_type)
{operator delete(_P); }
0401B90 push ebp
00401B91 mov ebp,esp
00401B93 sub esp,44h
00401B96 push ebx
00401B97 push esi
00401B98 push edi
00401B99 push ecx
00401B9A lea edi,[ebp-44h]
00401B9D mov ecx,11h
00401BA2 mov eax,0CCCCCCCCh
00401BA7 rep stos dword ptr [edi]
00401BA9 pop ecx
00401BAA mov dword ptr [ebp-4],ecx
00401BAD mov eax,dword ptr [ebp+8]
00401BB0 push eax
00401BB1 call operator delete (00403210) //这里真正调用是系统内置函数delete
00401BB6 add esp,4
00401BB9 pop edi
00401BBA pop esi
00401BBB pop ebx
00401BBC add esp,44h
00401BBF cmp ebp,esp
00401BC1 call __chkesp (00409c80)
00401BC6 mov esp,ebp
00401BC8 pop ebp
00401BC9 ret 8
//进入delop.cpp 文件的delete方法
void __cdecl operator delete(void *p) _THROW0()
{ // free an allocated object
free(p);
}
//DBGHEAP.C
_CRTIMP void __cdecl free(
void * pUserData
)
{
_free_dbg(pUserData, _NORMAL_BLOCK);
}
_CRTIMP void __cdecl _free_dbg(
#endif /* _MT */
void * pUserData,
int nBlockUse
)
{
_CrtMemBlockHeader * pHead;
/* verify heap before freeing */
if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
_ASSERTE(_CrtCheckMemory());
if (pUserData == NULL)
return;
/* forced failure */
if (!(*_pfnAllocHook)(_HOOK_FREE, pUserData, 0, nBlockUse, 0L, NULL, 0))
{
_RPT0(_CRT_WARN, "Client hook free failure.\n");
return;
}
/*
* If this ASSERT fails, a bad pointer has been passed in. It may be
* totally bogus, or it may have been allocated from another heap.
* The pointer MUST come from the 'local' heap.
*/
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
/* if we didn't already check entire heap, at least check this object */
if (!(_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF))
{
/* check no-mans-land gaps */
if (!CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize))
_RPT3(_CRT_ERROR, "DAMAGE: before %hs block (#%d) at 0x%08X.\n",
szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)],
pHead->lRequest,
(BYTE *) pbData(pHead));
if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize))
_RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.\n",
szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)],
pHead->lRequest,
(BYTE *) pbData(pHead));
}
if (pHead->nBlockUse == _IGNORE_BLOCK)
{
_ASSERTE(pHead->nLine == IGNORE_LINE && pHead->lRequest == IGNORE_REQ);
/* fill the entire block including header with dead-land-fill */
memset(pHead, _bDeadLandFill,
sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize);
_free_base(pHead);
return;
}
/* CRT blocks can be freed as NORMAL blocks */
if (pHead->nBlockUse == _CRT_BLOCK && nBlockUse == _NORMAL_BLOCK)
nBlockUse = _CRT_BLOCK;
/* Error if freeing incorrect memory type */
_ASSERTE(pHead->nBlockUse == nBlockUse);
/* keep track of total amount of memory allocated */
_lCurAlloc -= pHead->nDataSize;
/* optionally reclaim memory */
if (!(_crtDbgFlag & _CRTDBG_DELAY_FREE_MEM_DF))
{
/* remove from the linked list */
if (pHead->pBlockHeaderNext)
{
pHead->pBlockHeaderNext->pBlockHeaderPrev = pHead->pBlockHeaderPrev;
}
else
{
_ASSERTE(_pLastBlock == pHead);
_pLastBlock = pHead->pBlockHeaderPrev;
}
if (pHead->pBlockHeaderPrev)
{
pHead->pBlockHeaderPrev->pBlockHeaderNext = pHead->pBlockHeaderNext;
}
else
{
_ASSERTE(_pFirstBlock == pHead);
_pFirstBlock = pHead->pBlockHeaderNext;
}
/* fill the entire block including header with dead-land-fill */
memset(pHead, _bDeadLandFill,
sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize);
_free_base(pHead); //这里又进入了新释放
}
else
{
pHead->nBlockUse = _FREE_BLOCK;
/* keep memory around as dead space */
memset(pbData(pHead), _bDeadLandFill, pHead->nDataSize);
}
}
//进入文件free.c的_free_base函数
void __cdecl _free_base (void * pBlock)
{
PHEADER pHeader;
if (pBlock == NULL)
return;
if ( __active_heap == __V6_HEAP )
{
#ifdef _MT
_mlock( _HEAP_LOCK );
__try {
#endif /* _MT */
if ((pHeader = __sbh_find_block(pBlock)) != NULL)
__sbh_free_block(pHeader, pBlock);
#ifdef _MT
}
__finally {
_munlock( _HEAP_LOCK );
}
#endif /* _MT */
if (pHeader == NULL)
HeapFree(_crtheap, 0, pBlock);
}
else if ( __active_heap == __V5_HEAP )
{
__old_sbh_region_t *preg;
__old_sbh_page_t * ppage;
__old_page_map_t * pmap;
#ifdef _MT
_mlock(_HEAP_LOCK );
__try {
#endif /* _MT */
if ( (pmap = __old_sbh_find_block(pBlock, &preg, &ppage)) != NULL )
__old_sbh_free_block(preg, ppage, pmap);
#ifdef _MT
}
__finally {
_munlock(_HEAP_LOCK );
}
#endif /* _MT */
if (pmap == NULL)
HeapFree(_crtheap, 0, pBlock);
}
else // __active_heap == __SYSTEM_HEAP
HeapFree(_crtheap, 0, pBlock); //最终在这里释放了堆上分配的内存
return;
}
可以看到程序delete时候三次调用到allocator.deallocate(_Ptr - 1, _Res + 2);以释放全部的字符串.
至此,以上的小程序全部结束.