第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_count; */
11 public:
12     Test(int value = 0) : m_pCount(new int(0))
13     {
14         m_value = value;
15         /* m_count = 0; */
16     }
17
18     int getValue() const
19     {
20         /* m_count++; */
21         *m_pCount = *m_pCount + 1;
22         return m_value;
23     }
24
25     void setValue(int value)
26     {
27         /* m_count++; */
28         *m_pCount = *m_pCount + 1;
29         m_value = value;
30     }
31
32     int getCount() const
33     {
34         /* return m_count; */
35         return *m_pCount;
36     }
37
38     ~Test()
39     {
40         delete m_pCount;
41     }
42 };
43
44 int main(int argc, char *argv[])
45 {
46     Test t;
47
48     t.setValue(100);
49
50     cout << "t.m_value = " << t.getValue() << endl;
51     cout << "t.m_count = " << t.getCount() << endl;
52
53     const Test ct(200);
54
55     cout << "ct.m_value = " << ct.getValue() << endl;
56     cout << "ct.m_count = " << ct.getCount() << endl;
57
58     return 0;
59 }

使用mutable可以完成const对象的访问统计,但是不使用mutable也可以完成这个需求。

使用指针常量完成这个需求,不改变指针的值,但是可以改变指针指向的值。

运行结果如下:

实际工程中,mutable使用比较少。最好不要使用。

问题2:

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

被忽略的事实:

我们通过一些方法可以是new出来的对象位于静态存储区。

new是关键字,也是操作符,因此,可以重载new和delete。

工程中不建议全局重载new。

通过函数来对这两个操作符进行重载,一般情况下都是针对具体的类进行重载,所以new和delete的重载函数就是类的成员函数,并且这两个重载函数默认为静态成员函数,写不写static都是静态的。

静态存储区中创建动态对象:

 1 #include <iostream>
 2 #include <string>
 3
 4 using namespace std;
 5
 6 class Test
 7 {
 8     static const unsigned int COUNT = 4;
 9     static char c_buffer[];
10     static char c_map[];
11
12     int m_value;
13 public:
14     void* operator new (unsigned int size)
15     {
16         void* ret = NULL;
17
18         for(int i=0; i<COUNT; i++)
19         {
20             if( !c_map[i] )
21             {
22                 c_map[i] = 1;
23
24                 ret = c_buffer + i * sizeof(Test);
25
26                 cout << "succeed to allocate memory: " << ret << endl;
27
28                 break;
29             }
30         }
31
32         return ret;
33     }
34
35     void operator delete (void* p)
36     {
37         if( p != NULL )
38         {
39             char* mem = reinterpret_cast<char*>(p);
40             int index = (mem - c_buffer) / sizeof(Test);
41             int flag = (mem - c_buffer) % sizeof(Test);
42
43             if( (flag == 0) && (0 <= index) && (index < COUNT) )
44             {
45                 c_map[index] = 0;
46
47                 cout << "succeed to free memory: " << p << endl;
48             }
49         }
50     }
51 };
52
53 char Test::c_buffer[sizeof(Test) * Test::COUNT] = {0};
54 char Test::c_map[Test::COUNT] = {0};
55
56 int main(int argc, char *argv[])
57 {
58     cout << "===== Test Single Object =====" << endl;
59
60     Test* pt = new Test;
61
62     delete pt;
63
64     cout << "===== Test Object Array =====" << endl;
65
66     Test* pa[5] = {0};
67
68     for(int i=0; i<5; i++)
69     {
70         pa[i] = new Test;
71
72         cout << "pa[" << i << "] = " << pa[i] << endl;
73     }
74
75     for(int i=0; i<5; i++)
76     {
77         cout << "delete " << pa[i] << endl;
78
79         delete pa[i];
80     }
81
82     return 0;
83 }

第53行定义静态存储空间。

运行结果如下:

我们可以使用这种方法结合二阶构造法,可以限制一个类最多产生多少个对象。

单例模式仅仅是使一个创建一个对象,而在静态存储区创建类结合二阶构造模式可以完成n例模式。

问题3:

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

自定义对象的存储空间示例程序:

  1 #include <iostream>
  2 #include <string>
  3 #include <cstdlib>
  4
  5 using namespace std;
  6
  7 class Test
  8 {
  9     static unsigned int c_count;
 10     static char* c_buffer;
 11     static char* c_map;
 12
 13     int m_value;
 14 public:
 15     static bool SetMemorySource(char* memory, unsigned int size)
 16     {
 17         bool ret = false;
 18
 19         c_count = size / sizeof(Test);
 20
 21         ret = (c_count && (c_map = reinterpret_cast<char*>(calloc(c_count, sizeof(char)))));
 22
 23         if( ret )
 24         {
 25             c_buffer = memory;
 26         }
 27         else
 28         {
 29             free(c_map);
 30
 31             c_map = NULL;
 32             c_buffer = NULL;
 33             c_count = 0;
 34         }
 35
 36         return ret;
 37     }
 38
 39     void* operator new (unsigned int size)
 40     {
 41         void* ret = NULL;
 42
 43         if( c_count > 0 )
 44         {
 45             for(int i=0; i<c_count; i++)
 46             {
 47                 if( !c_map[i] )
 48                 {
 49                     c_map[i] = 1;
 50
 51                     ret = c_buffer + i * sizeof(Test);
 52
 53                     cout << "succeed to allocate memory: " << ret << endl;
 54
 55                     break;
 56                 }
 57             }
 58         }
 59         else
 60         {
 61             ret = malloc(size);
 62         }
 63
 64         return ret;
 65     }
 66
 67     void operator delete (void* p)
 68     {
 69         if( p != NULL )
 70         {
 71             if( c_count > 0 )
 72             {
 73                 char* mem = reinterpret_cast<char*>(p);
 74                 int index = (mem - c_buffer) / sizeof(Test);
 75                 int flag = (mem - c_buffer) % sizeof(Test);
 76
 77                 if( (flag == 0) && (0 <= index) && (index < c_count) )
 78                 {
 79                     c_map[index] = 0;
 80
 81                     cout << "succeed to free memory: " << p << endl;
 82                 }
 83             }
 84             else
 85             {
 86                 free(p);
 87             }
 88         }
 89     }
 90 };
 91
 92 unsigned int Test::c_count = 0;
 93 char* Test::c_buffer = NULL;
 94 char* Test::c_map = NULL;
 95
 96 int main(int argc, char *argv[])
 97 {
 98     char buffer[12] = {0};
 99
100     Test::SetMemorySource(buffer, sizeof(buffer));
101
102     cout << "===== Test Single Object =====" << endl;
103
104     Test* pt = new Test;
105
106     delete pt;
107
108     cout << "===== Test Object Array =====" << endl;
109
110     Test* pa[5] = {0};
111
112     for(int i=0; i<5; i++)
113     {
114         pa[i] = new Test;
115
116         cout << "pa[" << i << "] = " << pa[i] << endl;
117     }
118
119     for(int i=0; i<5; i++)
120     {
121         cout << "delete " << pa[i] << endl;
122
123         delete pa[i];
124     }
125
126     return 0;
127 }

15行的函数用于动态设置创建对象的地址。

结果如下:

被忽略的事实:

new[]和delete[]是新的操作符,不同于new和delete。

动态数组的内存管理:

 1 #include <iostream>
 2 #include <string>
 3 #include <cstdlib>
 4
 5 using namespace std;
 6
 7 class Test
 8 {
 9     int m_value;
10 public:
11     Test()
12     {
13         m_value = 0;
14     }
15
16     ~Test()
17     {
18     }
19
20     void* operator new (unsigned int size)
21     {
22         cout << "operator new: " << size << endl;
23
24         return malloc(size);
25     }
26
27     void operator delete (void* p)
28     {
29         cout << "operator delete: " << p << endl;
30
31         free(p);
32     }
33
34     void* operator new[] (unsigned int size)
35     {
36         cout << "operator new[]: " << size << endl;
37
38         return malloc(size);
39     }
40
41     void operator delete[] (void* p)
42     {
43         cout << "operator delete[]: " << p << endl;
44
45         free(p);
46     }
47 };
48
49 int main(int argc, char *argv[])
50 {
51     Test* pt = NULL;
52
53     pt = new Test;
54
55     delete pt;
56
57     pt = new Test[5];
58
59     delete[] pt;
60
61     return 0;
62 }

运行结果如下:

我们通过重载的方式说明了new 和new[]的不同,第57行的new调用的是34行的new[]重载,第57行5个元素占用20个字节,但是结果中却打印出了24个字节,这就是额外的空间记录数组的长度信息。这个长度信息用于记录调用析构函数的次数。

new[]和delete[]的使用必须匹配,不能和new、delete交叉使用。 例如new[]在栈上分配空间时,使用delete释放到堆上,这样就可能崩溃。或者使用delete只会调用一次析构函数。

小结:

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9601916.html

时间: 2024-08-29 17:30:27

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

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

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

第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 { *

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