69-技巧:自定义内存管理

1、问题1

这里写图片描述

2、mutable

这里写图片描述

3、mutable分析

这里写图片描述

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int m_value;
    int * const m_pCount;//技巧,对于const类对象和非const类对象都可以对该变量进行修改
    /* mutable int m_count; */
public:
    Test(int value = 0) : m_pCount(new int(0))
    {
        m_value = value;
        /* m_count = 0; */
    }

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

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

    int getCount() const
    {
        /* return m_count; */
        return *m_pCount;
    }

    ~Test()
    {
        delete m_pCount;
    }
};

int main(int argc, char *argv[])
{
    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;
}

4、问题2

这里写图片描述

5、

这里写图片描述

6、重载new/delete

这里写图片描述

7、

这里写图片描述

8、

这里写图片描述
通过重载new/delete操作符来进行,在静态存储区创建对象
通过这样的方法结合二阶构造方法 可以创建单例模式以外的N例模式(只能存在N个对象)

#include <iostream>
#include <string>

using namespace std;

class Test
{
    //定义一个静态成员空间的大小,可以容纳4个对象
    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++)
        {
            if( !c_map[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[Test::COUNT] = {0};

int main(int argc, char *argv[])
{
    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;//只能创建4个对象,第5个为空

        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: 0x6021a0
succeed to free memory: 0x6021a0
===== Test Object Array =====
succeed to allocate memory: 0x6021a0
pa[0] = 0x6021a0
succeed to allocate memory: 0x6021a4
pa[1] = 0x6021a4
succeed to allocate memory: 0x6021a8
pa[2] = 0x6021a8
succeed to allocate memory: 0x6021ac
pa[3] = 0x6021ac
pa[4] = 0
delete 0x6021a0
succeed to free memory: 0x6021a0
delete 0x6021a4
succeed to free memory: 0x6021a4
delete 0x6021a8
succeed to free memory: 0x6021a8
delete 0x6021ac
succeed to free memory: 0x6021ac
delete 0
9、问题3

这里写图片描述

10、

这里写图片描述

#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 (long 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: 0x7ffc2efe4ce0
succeed to free memory: 0x7ffc2efe4ce0
===== Test Object Array =====
succeed to allocate memory: 0x7ffc2efe4ce0
pa[0] = 0x7ffc2efe4ce0
succeed to allocate memory: 0x7ffc2efe4ce4
pa[1] = 0x7ffc2efe4ce4
succeed to allocate memory: 0x7ffc2efe4ce8
pa[2] = 0x7ffc2efe4ce8
pa[3] = 0
pa[4] = 0
delete 0x7ffc2efe4ce0
succeed to free memory: 0x7ffc2efe4ce0
delete 0x7ffc2efe4ce4
succeed to free memory: 0x7ffc2efe4ce4
delete 0x7ffc2efe4ce8
succeed to free memory: 0x7ffc2efe4ce8
delete 0
delete 0

11、

这里写图片描述

12、

这里写图片描述

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class Test
{
    int m_value;
public:
    Test()
    {
        m_value = 0;
    }

    ~Test()
    {
    }
    //new重载后的参数size 代表当前对象所占内存的大小,由编译器算出,我们使用的时候不用传大小,
    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);
    }

    //new[] 重载后的参数size 代表当前对象所占内存的大小,由编译器算出,size大于我们预估的内存大小,多余的内存主要用来存放数组的数据信息()长度等
    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: 0xb03030
operator new[]: 28
operator delete[]: 0xb03050
13、

这里写图片描述

14、小结

这里写图片描述

15、补充:关于new/delete操作符重载的解释

补充知识点:解决使用疑惑

http://www.51testing.com/html/51/n-858451.html

  1. 函数(Function)
     (1) operator new function
    void * ::operator new(size_t); //Global
    void * class-name::operator new(size_t); //Class
      上面是C++中operator new function的原型,一个是全局类型的,一个的类成员类型的。全局类型的operator new函数在下面两种情况下被调用:一种是在分配C++内建(built-in)类型的动态内存时,一种是在分配用户没有自己定义operator new成员函数的用户自定义类型的动态内存时。 如果用户在自己定义的类型中,定义了operator new函数,那么用户在用new申请该类型的动态内存时, 便会调用该类型的成员函数operator new, 而不是全局的operator new。
      另外,我们注意到,上面的原型中函数的返回值为void 类型, 第一个参数为size_t类型,这个是C++编译器要求的,如果要自己重载operator new函数,返回值必须为void 类型,第一个参数必须为size_t类型,否则,编译器会返回如下错误信息:

      (2) operator delete function
    void operator delete( void * );
    void operator delete( void *, size_t );
      上面是operator delete function的原型。operator delete function也有全局的和类成员的两种。这里需要注意,一个类只能有一个operator delete function做为其成员函数,而且必须为上面两种中的其中一种,没有其它的形式。如果一个类实现了自己的operator delete function成员函数,那么在释放该类型的内存时,编译器便会调用成员operator delete function, 而不是全局的。
      上面的两种原型,第一种,在调用的时候,编译器会把要释放的内存的首地址传入,第二种,在调用的时候,编译器会把要释放的内存的首地址和大小都传入。因此,可以利用这一特性,如果我们在基类中实现第二种形式的operator delete function的成员函数,那么便可以用之来释放子类类型的内存(具体参考最后面的例子)。
      
      2. 运算符(Operator)
      (1) new operator
      [::] new [placement] new-type-name [new-initializer]
      [::] new [placement] ( type-name ) [new-initializer]
      注:上面的’[]‘表示在其中的部分是optional(可选的)
      上面是new operator的原型。在C++中,动态内存的分配,通常都是调用new operator来完成的,利用new operator来分配动态内存,编译器要做下面两项工作:
      a. 调用operator new function分配内存(allocate the memory)
      b. 调用构造函数(call the constructor)来进行初始化
      下面来说一说new operator的原型中各部分到底是干什么的:
      placement: 如果你重载了operator new function, placement可以用来传递额外的参数
      type-name: 指定要分配的内存的类型,可以是内建(built-in)类型,也可以是用户自定义类型
      new-initializer: 指定对分配后内存的初始化的参数,也就的构造函数的参数 。这里需要注意一点,在分配一个对象的数组类型的内存时,不能够指定初始化参数;换言之,要想分配一个对象的数组类型的内存,该对象必须有缺省构造函数
      
      (2) delete opeartor
      [::] delete cast-expression
      [::] delete [ ] cast-expression
      上面是delete operator的原型,第一种用来释放普通的对象(包括内建类型)类型的内存,第二种用来释放对象的数组类型的内存。在C++中,用new operator分配的动态内存,必须调用delete operator来释放,通常用delete operator释放内存编译器要做下面两项工作:
      a. 调用对象析构函数来析构对象
      b. 调用operator delete function来释放内存(deallocate the memory)

      3. 关于new/delete使用过程中一些需要注意的点
      (1)如何区别operator new/delete function 与 new/delete operator ?
      通过上面的讲述,不难看出,我们分配/释放动态内存,调用的是new/delete operator, 而在调用new/delete的过程中,编译器会自动调用operator new/delete function来完成实际的内存分配/释放的工作
      (2) 用delete operator去释放一块不是由new operator释放的内存,结果是不可预料的,因此,切记,operator new与operator delete一定要配对使用,这是写好程序的基础
      (3) new operator调用失败会抛出std::bad_alloc异常,前提是你没有自己重载对应的operator new function;delete operator失败,常见的原因是多次delete同一块内存
      (4) 如果一块内存被delete后,再对它解引用(Dereference),结果也是不可预测的,很可能导致程序崩溃
      (5) delete一个空(NULL)指针是安全的,没有任何害处的
      (6) 类成员类型的operator new/delete函数必须为静态(static)函数,因此它们不能为虚函数(virtual function),也遵守public, protected, private的访问权限控制

    http://www.51testing.com/html/51/n-858451.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使上述CSS样式适应手机设备,您可以使用媒体查询来调整样式和布局。以下是在现有代码中添加媒体查询以适应手机设备的示例: ```css .page { /* 桌面样式 */ display: flex; flex-direction: column; align-items: flex-start; width: 375px; height: 812px; background-color: #000000; font-family: Roboto-Regular; white-space: nowrap; } .view { /* 桌面样式 */ position: relative; display: flex; flex-direction: column; align-items: flex-start; margin-top: 100px; margin-left: 52px; } .caption { /* 桌面样式 */ position: relative; overflow: hidden; height: 45px; max-width: 192px; font-family: Roboto-Bold; font-size: 32px; line-height: 45px; color: #ffffff; text-overflow: ellipsis; } .title { /* 桌面样式 */ position: relative; margin-top: 4px; font-size: 32px; line-height: 38px; color: #c3c3c3; } .item-wrapper { /* 桌面样式 */ position: relative; display: flex; justify-content: center; align-items: flex-start; margin-top: 69px; margin-left: 33px; white-space: normal; } .item { /* 桌面样式 */ width: 294px; height: 287px; } .book-wrapper { /* 桌面样式 */ position: relative; display: flex; align-items: center; align-self: flex-end; height: 49px; padding-left: 20px; padding-right: 20px; margin-top: 128px; margin-right: 50px; line-height: 20px; border-radius: 10px; box-sizing: border-box; border-width: 1px; border-style: solid; border-color: rgba(196, 196, 196, 1); } .book { /* 桌面样式 */ font-size: 20px; color: #ffffff; } button { /* 桌面样式 */ background-color: transparent; border-style: none; } /* 手机样式 */ @media (max-width: 480px) { .page { width: auto; height: auto; padding: 10px; } .view { margin-top: 50px; margin-left: 20px; } .caption { height: auto; max-width: none; font-size: 24px; line-height: 30px; text-overflow: initial; } .title { margin-top: 2px; font-size: 24px; line-height: 30px; } .item-wrapper { margin-top: 40px; margin-left: 20px; } .item { width: auto; height: auto; max-width: 100%; max-height: none; } .book-wrapper { margin-top: 80px; margin-right: 20px; } .book { font-size: 16px; } } ``` 在上述示例中,我们添加了一个媒体查询以应用适应手机设备的CSS样式。媒体查询的条件是最大宽度为480像素,这意味着当浏览器宽度小于或等于480像素时,将应用手机样式。在手机样式中,我们对各个元素进行了调整,以适应手机屏幕的大小和布局。 请注意,这只是一个示例,您可以根据您的具体需求和设计进行进一步的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值