第69课.技巧:自定义内存管理

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

注意:对象(普通对象,只读对象)

eg:

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int m_value;
    int * const m_pCount;
public:
    Test(int value = 0) : m_pCount(new int(0))
    {
        m_value = value;
    }

    int getValue() const
    {
        *m_pCount = *m_pCount + 1;
        return m_value;
    }

    void setValue(int value)
    {
        *m_pCount = *m_pCount + 1;
        m_value = value;
    }

    int getCount() const
    {
        return *m_pCount;
    }

    ~Test()
    {
        delete m_pCount;
    }
};

int main()
{
    // 普通对象
    Test t;

    t.setValue(100);

    cout << "t.m_value = " << t.getValue() << endl;
    cout << "t.m_count = " << t.getCount() << endl;

    // 只读对象
    const Test ct(200);
    cout << "ct.m_value = " << ct.getValue() << endl;
    cout << "ct.m_count = " << ct.getCount() << endl;

    return 0;
}

2.new关键字创建出来的对象位于什么地方?

答案:可以位于静态存储区,堆去,栈区

new与delete

a.new/delete的本质是c++预定义的操作符(可重载)
b.c++对这两个操作符做了严格的行为定义

?new
??1).获得足够大的内存空间(默认为堆空间
??2).在获取的空间中调用构造函数创建对象

?delete
??1).调用析构函数销毁对象
??2).归还对象所占用的空间(默认为堆空间

c.在c++中能够重载new/delete操作符
?1).全局重载(不推荐)
?2).局部重载(针对具体类进行重载)
重载new/delete的意义在于改变动态对象创建时的内存分配方式

new/delete的重载方式

// 默认为静态成员函数
void* operator new (unsigned int size)
{
    void* ret = NULL;

    /*    ret point to allocated memory    */

    return ret;
}

// 默认为静态成员函数
void operator delete(void* p)
{
    /*    free the memory which is pointed by p    */
}

new关键字创建的对象位于静态存储区

eg:

#include <iostream>
#include <string>

using namespace std;

class Test
{
    static const unsigned int COUNT = 4;
    static char c_buffer[];
    static char c_map[];

    int m_value;
public:
    void* operator new (unsigned int size)
    {
        void* ret = NULL;

        for(int i = 0; i < COUNT; i++)
        {
            c_map[i] = 1;

            ret = c_buffer + i * sizeof(Test);

            cout << "succeed to allocate memory: " << 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 << "succeed to free memory: " << p << endl;
            }
        }
    }
};

char Test::c_buffer[sizeof(Test) * Test::COUNT] = {0};
char Test::c_map[COUNT] = {0};

int main()
{
    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;
}

如何在指定的地址上创建c++对象(new在栈区创建对象)

解决方案:
?在类中重载new/delete操作符;在new的操作符重载函数中返回指定地址;在delete操作符重载中标记对应地址可用。

知识点:
calloc:
a.参数 : (个数,大小),例;(20, int);申请一个数组成员为20个int大小
b.初始化: 在动态分配完内存后,自动初始化该内存空间为零。
c.返回值: 函数返回值是一个数组。

eg:

#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);      // 确保size至少能存下一个Test

        // c_map初始化,一个数组。成员是c_count个char
        ret = (c_count && (c_map = reinterpret_cast<char*>(calloc(c_count, sizeof(char)))));

        if(ret)
        {
            c_buffer = memory;
        }
        else
        {
            // 如果指定到地址不能装下一个Test,或者c_map数组赋值失败。
            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()
{
    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;
}

3.new[]/delete 与 new/delete

new[]/delete 与 new/delete完全不同
a.动态对象数组创建通过new[]完成
b.动态对象数组的销毁通过delete[]完成
c.new[]/delete[]能够被重载,进而改变内存管理方式

注意:

a.new[]实际需要返回的内存空间可能比期望的要多。因为对象组占用的内存中需要保存数组信息
b.数组信息用于确定构造函数和析构函数的调用次数

重载方式

 // 默认为静态成员函数
void* operator new[] (unsigned int size)
{
    void* ret = NULL;

    /*    ret point to allocated memory    */

    return ret;
}

// 默认为静态成员函数
void operator delete[](void* p)
{
    /*    free the memory which is pointed by p    */
}

eg:

#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;
}

原文地址:https://www.cnblogs.com/huangdengtao/p/12040275.html

时间: 2024-10-12 04:15:55

第69课.技巧:自定义内存管理的相关文章

C++语言学习(二十)——自定义内存管理

C++语言学习(二十)--自定义内存管理 一.统计类对象中成员变量的访问次数 mutable是为了突破const函数的限制而设计的,mutable修饰的成员变量将永远处于可改变的状态.mutable成员变量破坏了只读对象的内部状态,而const成员函数保证只读对象的状态不变性,因此mutable成员变量无法保证只读对象状态的不变性. #include <iostream> using namespace std; class Test { public: Test():m_count(0) {

第69课 技巧,自定义内存管理

如何统计对象中某个成员变量的访问次数? 解法: 这里我们只能满足普通对象的访问统计,那么const对象呢? 完善解法,使得能统计只读对象的访问次数: 使用了mutable之后,只读对象名存实亡. 1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Test 7 { 8 int m_value; 9 int * const m_pCount; 10 /* mutable int m_

C++中的自定义内存管理

1,问题: 1,new 关键字创建出来的对象位于什么地方? 1,位于堆空间: 2,有没有可能位于其它地方? 1,有: 2,通过一些方式可以使动态创建的对象位于静态存储区: 3,这个存储区在程序结束后释放: 2,new/delete 被忽略的事实: 1,new/delete 的本质是 C++ 预定义的操作符: 1,new/delete 是关键字,但本质是预定义的操作符: 2,C++ 中操作符可以重载: 2,C++ 对这两个操作符做了严格的行为定义: 1,new: 1,获取足够大的内存空间(默认为堆

自定义内存管理(五十七)

一个笔试题:编写能统计对象中某个成员变量的访问次数的程序.我们在类中定义一个私有成员变量,在构造函数中初始化为 0,在进行读写操作时都 ++,那么就达到我们的目的了,下面我们看看程序是怎样写的 #include <iostream> #include <string> using namespace std; class Test {     int m_Value;     int m_count; public:     Test(int value = 0)     {   

《Effective C++》内存管理

如果global new-hander没有成功配置,会抛出一个std::bad_alloc的exception. #include<iostream> #include<new> #include<climits> using namespace std; template<class T> class NewHandlerSupport{ public: static new_handler set_new_handler(new_handler p);

内存管理 &amp; 内存优化技巧 浅析

内存管理 浅析 下列行为都会增加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户体验.如何让回收那些不再使用的对象呢?本文着重介绍OC中的内存管理. 所谓内存管理,就是对内存进行管理,涉及的操作有: 1.分配内存:比如创建一个对象,会增加内存占用: 2.清除内存:比如销毁一个对象,会减少内存占用. 内存管理的管理范围: 1.任何继承了NSObject的对象: 2.对其他非对象类

内存管理 浅析 内存管理/内存优化技巧

内存管理 浅析 下列行为都会增加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户体验.如何让回收那些不再使用的对象呢?本文着重介绍OC中的内存管理. 所谓内存管理,就是对内存进行管理,涉及的操作有: 1.分配内存:比如创建一个对象,会增加内存占用: 2.清除内存:比如销毁一个对象,会减少内存占用. 内存管理的管理范围: 1.任何继承了NSObject的对象: 2.对其他非对象类

Java内存管理的9个小技巧

Java内存管理的9个小技巧很多人都说“Java完了,只等着衰亡吧!”,为什么呢?最简单的的例子就是Java做的系统时非常占内存!一听到这样的话,一定会有不少人站出来为Java辩护,并举出一堆的性能测试报告来证明这一点.其实从理论上来讲Java做的系统并不比其他语言开发出来的系统更占用内存,那么为什么却有这么多理由来证明它确实占内存呢?两个字,陋习. 1.别用new Boolean(). 在很多场景中Boolean类型是必须的,比如JDBC中boolean类型的set与get都是通过Boolea

[C++]内存管理器--谈论如何自定义内存分配机制

内存管理器–谈论如何自定义内存分配机制 Memory pools, also called fixed-size blocks allocation, is the use of pools for memory management that allows dynamic memory allocation comparable to malloc or C++'s operator new. As those implementations suffer from fragmentation