zoukankan      html  css  js  c++  java
  • 第六十九课、自定义内存管理

    一、统计对象中某个成员变量的访问次数

    解决方法一:

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
    private:
        int i;
        mutable int m_count;
    public:
        Test(int v)
        {
            i = v;
            m_count = 0;
        }
        
        void setI(int v)
        {
            i = v;
            m_count++;
        }
        
        int getI() const  //方便const对象调用
        {
            m_count++;
            return i;
        }
        
        int getCount() const //方便const对象调用
        {
            return m_count;
        }
    };
    
    int main()
    {
        const Test t(2);//只读对象
        cout << t.getI() << endl;//2
        cout << t.getCount() << endl;//1
        
        return 0;
    }
    统计对象中某个成员变量的访问次数

    1.遗失的关键字:mutable

    (1)、mutable关键字是为了突破const函数的限制设计的

    (2)、mutable关键字将永远处于可改变的状态

    (3)、mutable关键字在实际项目中被严禁使用

    2、mutab的深入分析

    (1)、mutable破坏了只读对象内部的状态

    (2)、const成员函数保证只读对象内部的状态不变性

    (3)、mutable成员变量的出现无法保证状态不变性

    解决方法二:

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
    private:
        int i;
        int * const m_count;//左数右指,const在*左边表示指针指向的地址中的数据是常量,在右说明指针本身是常量
    public:
        Test(int v = 0) : m_count(new int(0))//const变量要在初始化列表中进行初始化
        {
            i = v;
    
        }
        
        void setI(int v)
        {
            i = v;
            *m_count = *m_count + 1;
        }
        
        int getI() const  //方便const对象调用
        {
            *m_count = *m_count + 1;//巧妙!!!只读成员函数里并没有改变成员变量的值
            return i;
        }
        
        int getCount() const //方便const对象调用
        {
            return *m_count;
        }
        
        ~Test()
        {
            delete m_count;
        }
    };
    
    int main()
    {
        const Test t(2);//只读对象
        cout << t.getI() << endl;//2
        cout << t.getCount() << endl;//1
        
        return 0;
    }
    统计对象中对某个变量的访问次数

    二、new/delete的本质是c++预定义的操作符

    1、c++对这两个操作符做了严格的行为定义

    new:

    (1)、获取足够大的内存空间(默认为堆空间

    (2)、在获取的空间中调用构造函数创建对象

    delete:

    (1)、调用析构函数销毁对象

    (2)、归还对象所占用的空间(默认为堆空间)

    2、c++中能够重载new/delete操作符(意义在于改变动态对象创建时的内存分配方式)

    (1)、全局重载(不推荐)

    (2)、局部重载(针对具体类进行重载)

    3、new/delete的重载方式(都是static的)

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
    private:
        static const unsigned int COUNT = 4;//最多分配4个Test大小
        static char c_buffer[];//分配空间
        static char c_map[];//用来标记哪个空间可以用
        int m_value;
    public:
        Test()
        {
        }
        
        void * operator new(unsigned int size)
        {
            void* ret = NULL;
            
            for(int i=0; i<COUNT; i++)
            {
                if( !c_map[i] )
                {
                    ret = c_buffer + i*sizeof(Test);
                    
                    c_map[i] = 1;
                    
                    cout << "succed to new a object:" << ret << endl;
                    
                    break;
                }
            }
            
            return ret; 
        }
        
        void operator delete(void* p)
        {
            if(p != NULL)
            {
                char* mem = reinterpret_cast<char*>(p);
                int index = (mem - c_buffer) / sizeof(Test);
                int flag = (mem - c_buffer) % sizeof(Test);//要保证位置合法
                
                if( (flag == 0) && (0 <= index) && (index < COUNT) )
                {
                    c_map[index] = 0;
                    cout << "succed to delete a object: " << p << endl;
                }
            }
        }
        
    
    };
    
    char Test::c_buffer[sizeof(Test)*Test::COUNT] = {0};
    char Test::c_map[COUNT] = {0};
    
    int main()
    {    
        Test* pa[5] = {0};
      
        for(int i=0; i<5; i++)
        {
            pa[i] = new Test;
            cout << "new " << "pa[" << i << "]=" << pa[i] << endl;
        }
        
          
        for(int i=0; i<5; i++)
        {  
            cout << "delete " << "pa[" << i << "]=" << pa[i] << endl;
            delete pa[i];
        }
        
        
        return 0;
    }
    //输出结果
    /*
    succed to new a object:0x804a0d4
    new pa[0]=0x804a0d4
    succed to new a object:0x804a0d8
    new pa[1]=0x804a0d8
    succed to new a object:0x804a0dc
    new pa[2]=0x804a0dc
    succed to new a object:0x804a0e0
    new pa[3]=0x804a0e0
    new pa[4]=0
    delete pa[0]=0x804a0d4
    succed to delete a object: 0x804a0d4
    delete pa[1]=0x804a0d8
    succed to delete a object: 0x804a0d8
    delete pa[2]=0x804a0dc
    succed to delete a object: 0x804a0dc
    delete pa[3]=0x804a0e0
    succed to delete a object: 0x804a0e0
    delete pa[4]=0
    
    */
    静态存储区分配空间

    三、在指定地址上创建c++对象

    1、重载new/delete

    (1)、在类中重载new/delete操作符

    (2)、在new操作符重载函数中返回指定地址

    (3)、在delete操作符重载函数中标记对应的地址可用

    #include <iostream>
    #include <string>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        static unsigned int c_count;
        static char* c_buffer;
        static char* c_map;
        
        int m_value;
    public:
        static bool SetMemorySource(char* memory, unsigned int size)
        {
            bool ret = false;
            
            c_count = size / sizeof(Test);
            
            ret = (c_count && (c_map = reinterpret_cast<char*>(calloc(c_count, sizeof(char)))));
            
            if( ret )
            {
                c_buffer = memory;
            }
            else
            {
                free(c_map);
                
                c_map = NULL;
                c_buffer = NULL;
                c_count = 0;
            }
            
            return ret;
        }
        
        void* operator new (unsigned int size)
        {
            void* ret = NULL;
            
            if( c_count > 0 )
            {
                for(int i=0; i<c_count; i++)
                {
                    if( !c_map[i] )
                    {
                        c_map[i] = 1;
                        
                        ret = c_buffer + i * sizeof(Test);
                        
                        cout << "succeed to allocate memory: " << ret << endl;
                        
                        break;
                    }
                }
            }
            else
            {
                ret = malloc(size);
            }
            
            return ret;
        }
        
        void operator delete (void* p)
        {
            if( p != NULL )
            {
                if( c_count > 0 )
                {
                    char* mem = reinterpret_cast<char*>(p);
                    int index = (mem - c_buffer) / sizeof(Test);
                    int flag = (mem - c_buffer) % sizeof(Test);
                    
                    if( (flag == 0) && (0 <= index) && (index < c_count) )
                    {
                        c_map[index] = 0;
                        
                        cout << "succeed to free memory: " << p << endl;
                    }
                }
                else
                {
                    free(p);
                }
            }
        }
    };
    
    unsigned int Test::c_count = 0;
    char* Test::c_buffer = NULL;
    char* Test::c_map = NULL;
    
    int main(int argc, char *argv[])
    {
        char buffer[12] = {0};
        
        Test::SetMemorySource(buffer, sizeof(buffer));
        
        cout << "===== Test Single Object =====" << endl;
         
        Test* pt = new Test;
        
        delete pt;
        
        cout << "===== Test Object Array =====" << endl;
        
        Test* pa[5] = {0};
        
        for(int i=0; i<5; i++)
        {
            pa[i] = new Test;
            
            cout << "pa[" << i << "] = " << pa[i] << endl;
        }
        
        for(int i=0; i<5; i++)
        {
            cout << "delete " << pa[i] << endl;
            
            delete pa[i];
        }
        
        return 0;
    }
    
    //输出结果
    /*
    ===== Test Single Object =====
    succeed to allocate memory: 0xbfbc38f0
    succeed to free memory: 0xbfbc38f0
    ===== Test Object Array =====
    succeed to allocate memory: 0xbfbc38f0
    pa[0] = 0xbfbc38f0
    succeed to allocate memory: 0xbfbc38f4
    pa[1] = 0xbfbc38f4
    succeed to allocate memory: 0xbfbc38f8
    pa[2] = 0xbfbc38f8
    pa[3] = 0
    pa[4] = 0
    delete 0xbfbc38f0
    succeed to free memory: 0xbfbc38f0
    delete 0xbfbc38f4
    succeed to free memory: 0xbfbc38f4
    delete 0xbfbc38f8
    succeed to free memory: 0xbfbc38f8
    delete 0
    delete 0
    
    */
    在指定地址分配空间

     2、new[]/delete[]和new/delete 完全不同

    (1)、动态对象数组的创建通过new[]完成

    (2)、动态对象数组销毁通过delete[]完成

    (3)、new[]/delete[]可以被重载,进而改变内存管理方式

    注意事项:

    (1)、new[]返回的地址空间可能比期望的多(原因如2、3)

     (2)、对象数组中占用的内存中需要保存数组信息(不然怎么知道调用多少次构造和析构函数?)

    (3)、数组信息用于确定构造函数和析构函数的调用次数

    #include <iostream>
    #include <string>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        int m_value;
    public:
        Test()
        {
            m_value = 0;
        }
        
        ~Test()
        {
        }
        
        void* operator new (unsigned int size)
        {
            cout << "operator new: " << size << endl;
            
            return malloc(size);
        }
        
        void operator delete (void* p)
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned int size)
        {
            cout << "operator new[]: " << size << endl;
            
            return malloc(size);
        }
        
        void operator delete[] (void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    int main(int argc, char *argv[])
    {
        Test* pt = NULL;
        
        pt = new Test;
        
        delete pt;
        
        pt = new Test[5];
        
        delete[] pt;
        
        return 0;
    }
    //输出结果
    /*
    operator new: 4
    operator delete: 0x8463008
    operator new[]: 24
    operator delete[]: 0x8463018
    */
    new[]分配的空间比预期的多

    四、小结

    (1)、new/delete本质为操作符

    (2)、可以通过全局函数重载new/delete(不推荐)

    (3)、可以针对具体类重载new/delete 

    (4)、new[]/delete[]与new/delete 完全不同

    (5)、new[]/delete[]也是可以被重载的操作符

    (6)、new[]返回的地址空间可能比期望的多

     

  • 相关阅读:
    Python Django开发遇到的坑(版本不匹配)
    Mysql安装与问题合集
    git branch -r查看不了远程所有分支
    angularJS使用$http请求下载excel表格
    遍历formData对象数据
    按需使用CryptoJS之AES加密(CFB)模式
    git之创建、删除分支
    git pull时报错:Access Denied (拒绝访问)
    angularJS监听数据变化
    Angular-ui-router入门
  • 原文地址:https://www.cnblogs.com/gui-lin/p/8624208.html
Copyright © 2011-2022 走看看