当前位置:   article > 正文

【C++深度解析】52、重载new/delete,在静态存储区、栈上分配空间_c++重载new

c++重载new

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

new首先获取足够大的内存空间,默认为堆空间,在获取的空间中调用构造函数创建对象。delete 调用析构函数销毁对象,归还对象所占的空间

在 C++ 中能够重载 new/delete 操作符,推荐在类中进行局部重载,默认为静态成员函数,不写 static 也是静态成员函数,不推荐全局重载,重载的意义在于改变对象创建时的内存分配方式
在这里插入图片描述
有了 new/delete 重载,就可以改变对象创建时的内存分配方式,不一定在堆中分配内存,可以在静态存储区,栈中创建对象。

1 静态存储区中创建对象

在类中使用 static 成员变量定义静态存储区的空间,并定义标志,用于表示每块内存是否被占用,空闲为 0,使用中为 1。new 申请空间时,在静态存储空间中寻找一个空闲空间,返回地址。delete 时,检查内存合法后将标志置为 0,表示内存不使用了。

// 52-1.cpp
#include <iostream>
#include <string>
using namespace std;

class Test
{
    static const unsigned int COUNT = 4;	// 最多存放的对象数量
    static char c_buffer[];					// 对象的存储空间
    static char c_map[];					// 每个存储对象位置是否空间,0表示空间可用
    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;							// 标志置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;
        cout << "pa[" << i << "]" << pa[i] << endl;
    }
    for (int i = 0; i < 5; i++)
    {
        cout << "delete " << pa[i] << endl;
        delete pa[i];
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

主函数中 Test* pa[5] 申请 5 个对象的空间,实际最多只能申请 4 个,所以最后一个申请不成功。

编译运行:

==== Test Single Object ====
succeed to allocate memory: 00CBC5AC
succeed to free memory: 00CBC5AC
==== Test Object Array ====
succeed to allocate memory: 00CBC5AC
pa[0]00CBC5AC
succeed to allocate memory: 00CBC5B0
pa[1]00CBC5B0
succeed to allocate memory: 00CBC5B4
pa[2]00CBC5B4
succeed to allocate memory: 00CBC5B8
pa[3]00CBC5B8
pa[4]00000000
delete 00CBC5AC
succeed to free memory: 00CBC5AC
delete 00CBC5B0
succeed to free memory: 00CBC5B0
delete 00CBC5B4
succeed to free memory: 00CBC5B4
delete 00CBC5B8
succeed to free memory: 00CBC5B8
delete 00000000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2 在指定地址上创建对象

如何在指定地址上创建 C++ 对象?

// 52-2.cpp
#include <iostream>
#include <string>
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

main 函数中的 buffer[12] 在栈中分配空间,将这个地址指定为 new 申请对象的地址,则 new 在栈中分配空间。

C++ 类中成员函数,static 变量不计算入 sizeof,buffer[12] 大小为 12 个字节,Test 大小为 4 字节,所以最多可以放置三个对象,我们申请了 5 个对象,所以只有前三个对象对申请成功。

编译运行

==== Test Single Object ====
succeed to allocate memory: 00B5FE20
succeed to free memory: 00B5FE20
==== Test Object Array ====
succeed to allocate memory: 00B5FE20
pa[0]00B5FE20
succeed to allocate memory: 00B5FE24
pa[1]00B5FE24
succeed to allocate memory: 00B5FE28
pa[2]00B5FE28
pa[3]00000000
pa[4]00000000
delete 00B5FE20
succeed to free memory: 00B5FE20
delete 00B5FE24
succeed to free memory: 00B5FE24
delete 00B5FE28
succeed to free memory: 00B5FE28
delete 00000000
delete 00000000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3 小结

1、new/delete 操作符可以重载,推荐针对具体类重载
2、new 默认在堆上分配空间,重载可以在静态存储区、栈上分配空间

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/876151
推荐阅读
  

闽ICP备14008679号