现在的位置: 首页 > 综合 > 正文

ISO C++基本类型和变量(转载)

2011年07月21日 ⁄ 综合 ⁄ 共 30363字 ⁄ 字号 评论关闭

基本类型和变量.
    像其他高级语言一样,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);以释放全部的字符串.
至此,以上的小程序全部结束.

抱歉!评论已关闭.