第六十九课、自定义内存管理

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

解决方法一:ios

#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函数的限制设计的c++

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

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

二、mutab的深刻分析

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

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

(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; }
统计对象中对某个变量的访问次数

2、new/delete的本质是c++预约义的操做符

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

new:code

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

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

delete:

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

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

二、c++中可以重载new/delete操做符(意义在于改变更态对象建立时的内存分配方式)

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

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

三、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 */
静态存储区分配空间

3、在指定地址上建立c++对象

一、重载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 */
在指定地址分配空间

 二、new[]/delete[]和new/delete 彻底不一样

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

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

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

注意事项:

(1)、new[]返回的地址空间可能比指望的多(缘由如二、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[]分配的空间比预期的多

4、小结

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

(2)、能够经过全局函数重载new/delete(不推荐)

(3)、能够针对具体类重载new/delete 

(4)、new[]/delete[]与new/delete 彻底不一样

(5)、new[]/delete[]也是能够被重载的操做符

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

相关文章
相关标签/搜索