自己写的内存池管理程序

来源:互联网 发布:小狐仙网络电影 编辑:程序博客网 时间:2024/05/18 01:22
测试用例还不够,希望有大虾测测 反馈意见。该程序还把线程锁,自动锁及operator new重载实现了下,测试没问题。
#include <iostream>#include <stdlib.h>#include <stdio.h>#include <time.h>#include <new>#include <string.h>using namespace std;#ifdef WIN32#include <windows.h>#else#include <pthread.h>#endifusing namespace std;/* 多线程锁,同一个线程尽管锁住也可以访问临界资源 */class myThreadLock{public:myThreadLock();~myThreadLock();void Lock();void unLock();private:#ifdef WIN32    CRITICAL_SECTION win_critical_section;#else    pthread_mutex_t linux_mutex;#endif};void myThreadLock::Lock(){#ifdef WIN32EnterCriticalSection(&win_critical_section);#elsepthread_mutex_lock(&linux_mutex);#endif}void myThreadLock::unLock(){#ifdef WIN32LeaveCriticalSection(&win_critical_section);#elsepthread_mutex_unlock(&linux_mutex);#endif}myThreadLock::myThreadLock(){#ifdef WIN32InitializeCriticalSection(&win_critical_section);#elsepthread_mutex_init(&linux_mutex, NULL);#endif}myThreadLock::~myThreadLock(){#ifdef WIN32DeleteCriticalSection(&win_critical_section);#elsepthread_mutex_unlock(&linux_mutex);#endif}/* 自动解锁类 */class AutoMutex{public:AutoMutex(myThreadLock *lock){pThreadLock = lock;if(pThreadLock != NULL)pThreadLock->Lock();}~AutoMutex(){if(pThreadLock != NULL)pThreadLock->unLock();}private:myThreadLock* pThreadLock;};/*************************************************(1)小内存:     pUsedList[]: [8]  [16]  [32]  [64]  [128]......   ↓ ↓  ↓   ↓   ↓  [8]  [16]  [32]  [64]  [128]......   ↓ ↓  ↓   ↓   ↓  [8]  [16]  [32]  [64]  [128]    .......         pFreeList[]: [8]  [16]  [32]  [64]  [128]......   ↓ ↓  ↓   ↓   ↓  [8]  [16]  [32]  [64]  [128]......   ↓ ↓  ↓   ↓   ↓  [8]  [16]  [32]  [64]  [128]    .......(2)大内存:链表结构: pBlockListHead[0]<->block1[size1]<->block2[size2]<->.........分配内存: 大的内存块由一个双向链表来管理,每次分配找到一个空闲节点A,判断该空闲节点A 的size是否满足需要分配的大小,如果该节点A 分配完以后还有剩余大于或等于最小blockSize 则新建个节点B,然后把该节点A 的使用标志置为1,新建节点B 的大小为A 节点分配后剩余的内存空间大小。释放内存: 找到要释放的内存地址相符的节点,将该节点的使用标志置为0,同时判断该节点的前后节点是否被使用,如果没有被使用则将前后没被使用的节点合并为一个节点使该节点的size更大,小的内存得以回收。*************************************************/#define BIG_MEMORY_SIZE (5 * 1024 * 1024) //5 M#define SMALL_MEMORY_MAX_SIZE  (1024)#define BIG_MEMORY_BLOCK_MAX_NUM ((BIG_MEMORY_SIZE) / (SMALL_MEMORY_MAX_SIZE + 4))typedef struct smNode{void* start_addr;struct smNode *next;}SmNode, *pSmNode;/* small memroy list struct */typedef struct SmBlockList{pSmNode pUsedList;pSmNode pFreeList;void **pBlockFirstAddr; /* 保存小内存池各个档次size 所分配内存的起始地址 */unsigned int *pBlockSize; /* 小内存池各个档次size 分配内存的总大小 */}st_SmBlockList;typedef struct bigNode{void* start_addr;unsigned int size;unsigned char usedFlag;//unsigned char reserved[3]; struct bigNode *next;struct bigNode *prev;}BigNode, *pBigNode;#define TEST_BIGMM (0)  /* Test the big memory alloc *//* big memory list struct */typedef struct BigBlockList{pBigNode pBlockListHead;pBigNode pSearchStartNode;unsigned int blockCount;       //当前已使用和未使用的block个数#if TEST_BIGMM  /* for test */unsigned int remainSize;       //所有未被使用的总内存unsigned int unUsedBlockNum;   //当前未被使用的block的个数#endifunsigned int minSizePerBlock;  //每个block最小的分配size}st_BigBlockList;/* 小内存各档次size定义,最后一个用于分配大内存链表节点 */enum{SML_8 = 8,SML_16 = 16,SML_32 = 32,SML_64 = 64,SML_128 = 128,SML_256 = 256,SML_512 = 512,SML_1024 = 1024,BIG_NODE = sizeof(BigNode)  /* 大内存链表节点大小 */};/* 小内存各档次节点数 */enum{SML8_N = 3000,SML16_N = 3000,SML32_N = 3000,SML64_N = 3000,SML128_N = 3000,SML256_N = 1500,SML512_N = 1500,SML1024_N = 1500,BIGNODE_N = BIG_MEMORY_BLOCK_MAX_NUM + 1};/* 存储小内存各档次大小数组定义 */static int s_small_memory_size[] = {SML_8,SML_16, SML_32,SML_64,SML_128,SML_256,SML_512,SML_1024,BIG_NODE};  //bytes/* 存储小内存各档次节点数数组定义 */static int s_small_memory_num[] = {SML8_N,SML16_N,SML32_N,SML64_N,SML128_N,SML256_N,SML512_N,SML1024_N,BIGNODE_N};class MemoryManage   //内存管理{public:MemoryManage();~MemoryManage();void* Malloc(size_t size);void Free(void* addr);pBigNode GetBigListHead() const;private:void BigMemInit();void BigMemDeInit();void* MallocBigMemory(size_t size);void FreeBigMemory(void* addr);void SmlMemInit();void SmlMemDeInit();void* GetFreeSmNode(int index);  /*move the smNode from freeList to usedList; and return pSmNode->start_addr */void RetUsedSmNode(int index, void* addr); /* move the smNode from usedList to freeList */void* MallocSmlMemory(size_t size);void FreeSmlMemory(void* addr);void* firstAddr;void* smlListFirstAddr;int total_small_list_head;int total_small_node_num;int total_big_size;void* bigMmFirstAddr;st_SmBlockList sm_block_list;st_BigBlockList bg_block_list;myThreadLock smLock;  /**< 小内存分配线程锁*/myThreadLock bgLock;   /**< 大内存分配线程锁*/};/* 构造函数初始化内存池 */MemoryManage::MemoryManage(){int total_small_size = 0, big_size = 0, small_node_num = 0;int i = 0;/* 小内存总链表数 */total_small_list_head = sizeof(s_small_memory_size) / sizeof(s_small_memory_size[0]);for(; i < total_small_list_head; ++i){total_small_size += s_small_memory_size[i] * s_small_memory_num[i];small_node_num += s_small_memory_num[i];}total_small_node_num = small_node_num;/* 4字节对齐 */total_big_size = ((BIG_MEMORY_SIZE) & (~(sizeof(int) - 1))) + sizeof(int);total_small_size = (total_small_size & (~(sizeof(int) - 1))) + sizeof(int);cout << "small node total num = " << total_small_node_num << endl;cout << "total small  size: " << total_small_size;cout << "; total big size: " << total_big_size << endl;/*  System malloc all memory */firstAddr = malloc(total_small_size + total_big_size);if(firstAddr == NULL){cout << "malloc all memory fail!" << endl;exit(-1);}bigMmFirstAddr = (unsigned char*)firstAddr + total_small_size;smlListFirstAddr = NULL;/* create small memory list */SmlMemInit();/* create big memory list */BigMemInit();}/* 析构函数释放内存池 */MemoryManage::~MemoryManage(){BigMemDeInit();  /* free list */SmlMemDeInit(); total_big_size = 0;bigMmFirstAddr = NULL;if(firstAddr != NULL){free(firstAddr);firstAddr = NULL;}}/* 对外提供的Malloc 接口 */void* MemoryManage::Malloc(size_t size){void* addr = NULL;if(size <= 0 || size > total_big_size)return NULL;/* 如果需要分配的size 大于等于大内存每个block的最小size */if(size >= bg_block_list.minSizePerBlock){/* 锁住 */AutoMutex auto_mutex(&bgLock);//cout << "malloc big memory!" << endl;return MallocBigMemory(size);}else{/* 锁住 */AutoMutex auto_mutex(&smLock);//cout << "malloc i = " << i << endl;return MallocSmlMemory(size);}return addr;}/* 对外提供的Free 接口 */void MemoryManage::Free(void* addr){if(addr == NULL)return;if(addr >= bigMmFirstAddr){/* 锁住 */AutoMutex auto_mutex(&bgLock);//cout << "free big memory!" << endl;FreeBigMemory(addr);}else{/* 锁住 */AutoMutex auto_mutex(&smLock);FreeSmlMemory(addr);}return;}/* 获得大内存链表头节点 */pBigNode MemoryManage::GetBigListHead() const{return bg_block_list.pBlockListHead;}/* 管理大内存的链表初始化 */void MemoryManage::BigMemInit(){bg_block_list.blockCount = 1;pBigNode pHead = (pBigNode)GetFreeSmNode(total_small_list_head - 1);if(pHead == NULL){cout << "BigMemInit() malloc pHead error!!!!" << endl;exit(-1);}bg_block_list.pBlockListHead = pHead;pHead->size = 0;pHead->start_addr = NULL;pHead->usedFlag = 1;pHead->prev = NULL;pBigNode pNew = (pBigNode)GetFreeSmNode(total_small_list_head - 1);if(pNew == NULL){cout << "BigMemInit() malloc pNew error!!!!" << endl;exit(-1);}pNew->next = NULL;pNew->size = total_big_size;pNew->start_addr = bigMmFirstAddr;pNew->usedFlag = 0;pHead->next = pNew;pNew->prev = pHead;bg_block_list.pSearchStartNode = pNew;#if TEST_BIGMMbg_block_list.unUsedBlockNum = 1;bg_block_list.remainSize = total_big_size;#endifbg_block_list.minSizePerBlock = (SMALL_MEMORY_MAX_SIZE  & (~(sizeof(int) - 1))) + sizeof(int);return;}/* 归还大内存链表节点的内存空间 */void MemoryManage::BigMemDeInit(){pBigNode pCur = bg_block_list.pBlockListHead;while(pCur){pBigNode pTmp = pCur;pCur = pCur->next;RetUsedSmNode(total_small_list_head - 1, pTmp);pTmp = NULL;}cout << "*************** BigMemDeInit Success !!!*******************" << endl;}void* MemoryManage::MallocBigMemory(size_t mem_size){size_t size = mem_size;/* 判断开始搜索的节点块大小是否满足要求 */if((bg_block_list.pSearchStartNode->size < size) || (bg_block_list.pSearchStartNode->usedFlag == 1))bg_block_list.pSearchStartNode = bg_block_list.pBlockListHead->next;  //如果不满足则从头开始寻找size_t sTmp = mem_size;pBigNode pCur = bg_block_list.pSearchStartNode;while(1){if(pCur != NULL ){if(size < bg_block_list.minSizePerBlock){size = bg_block_list.minSizePerBlock;}if((pCur->usedFlag == 0) && (pCur->size >= size)){if((pCur->size - size) >= bg_block_list.minSizePerBlock){pBigNode pNew = (pBigNode)GetFreeSmNode(total_small_list_head - 1);if(pNew == NULL){cout << "********************************" << endl;return NULL;}/* 一片大内存区域最多只能形成BIG_MEMORY_BLOCK_MAX_NUM 块区域 */bg_block_list.blockCount++;if(bg_block_list.blockCount > BIG_MEMORY_BLOCK_MAX_NUM){cout << "@@@@@@@@@@@@@@@@@@@@@@@" << endl;return NULL;}pNew->next = pCur->next;if(pCur->next != NULL)pCur->next->prev = pNew;pNew->size = pCur->size - size;pNew->start_addr = (unsigned char*)pCur->start_addr + size;pNew->usedFlag = 0;pCur->usedFlag = 1;pCur->next = pNew;pNew->prev = pCur;pCur->size = size;bg_block_list.pSearchStartNode = pNew;#if TEST_BIGMMbg_block_list.remainSize -= size;#endifreturn pCur->start_addr;}else{pCur->usedFlag = 1;#if TEST_BIGMMbg_block_list.unUsedBlockNum--;bg_block_list.remainSize -= size;#endifreturn pCur->start_addr;}}else{pCur = pCur->next;}}elsebreak;}cout << "Return NULL#########, sTmp = " << sTmp << ";size= " << size << endl;return NULL;}void MemoryManage::FreeBigMemory(void* addr){pBigNode pCur = bg_block_list.pBlockListHead->next;while(1){if(pCur == NULL){cout << "free big memory error!!! " << endl;break;}if((pCur->usedFlag == 1) && (pCur->start_addr == addr)){#if TEST_BIGMMbg_block_list.remainSize += pCur->size;#endif/* free该节点时,判断它后面的节点是否被使用,如果未被使用则把它们合并成一个大内存块(内存碎片回收) */pBigNode pBack = pCur->next;pBigNode pPrev = pCur->prev;while((pBack != NULL) && (pBack->usedFlag == 0)){pCur->next = pBack->next;if(pBack->next != NULL)pBack->next->prev = pCur;pCur->size += pBack->size;pBigNode pfree = pBack;pBack = pBack->next;if(bg_block_list.pSearchStartNode == pfree){bg_block_list.pSearchStartNode = pCur;}RetUsedSmNode(total_small_list_head - 1 ,pfree);  /* free node */pfree = NULL;bg_block_list.blockCount--;#if TEST_BIGMMbg_block_list.unUsedBlockNum--;#endif}/* free该节点时,判断它前面的节点是否被使用,如果未被使用则把它们合并成一个大内存块(内存碎片回收) */while((pPrev != NULL) && (pPrev->usedFlag == 0)){pCur->prev = pPrev->prev;if(pPrev->prev != NULL)pPrev->prev->next = pCur;pCur->size += pPrev->size;pCur->start_addr = pPrev->start_addr;pBigNode pfree = pPrev;pPrev = pPrev->prev;if(bg_block_list.pSearchStartNode == pfree){bg_block_list.pSearchStartNode = pCur;}RetUsedSmNode(total_small_list_head - 1 ,pfree);  /* free node */pfree = NULL;bg_block_list.blockCount--;#if TEST_BIGMMbg_block_list.unUsedBlockNum--;#endif}pCur->usedFlag = 0;#if TEST_BIGMMbg_block_list.unUsedBlockNum++;#endifreturn;}elsepCur = pCur->next;}return;}/* 小内存池链表的建立及初始化 */void MemoryManage::SmlMemInit(){/* 建立各个档次链表的头节点 */smlListFirstAddr = malloc(total_small_list_head * 2 * sizeof(SmNode)  /* total small memory list head space */+ total_small_node_num * sizeof(SmNode));   /* total small memory list node space*/if(smlListFirstAddr == NULL){cout << "malloc smlListFirstAddr fail!!! " << endl;exit(-1);}void* smListNodeAddr = smlListFirstAddr;memset(smListNodeAddr, 0, sizeof(SmNode) * total_small_list_head * 2);sm_block_list.pFreeList = (pSmNode)smListNodeAddr;sm_block_list.pUsedList = (pSmNode)(sm_block_list.pFreeList + total_small_list_head);sm_block_list.pBlockSize = (unsigned int*)malloc(sizeof(unsigned int) * total_small_list_head);if(sm_block_list.pBlockSize == NULL){cout << "malloc pBlockSize error!!" << endl;exit(-1);}memset(sm_block_list.pBlockSize, 0, sizeof(unsigned int) * total_small_list_head);sm_block_list.pBlockFirstAddr = (void**)malloc(sizeof(void*) * total_small_list_head);if(sm_block_list.pBlockFirstAddr == NULL){cout << "malloc blockfirst addr error!!" << endl;exit(-1);}memset(sm_block_list.pBlockFirstAddr, 0, sizeof(void*) * total_small_list_head);pSmNode pNodeAddr = (pSmNode)smListNodeAddr + total_small_list_head * 2;/*  create small memory list */int count = 0, i = 0;for(i = 0; i < total_small_list_head; ++i){int j = 0;static int preCount = 0;pSmNode pTmp = &sm_block_list.pFreeList[i];sm_block_list.pFreeList[i].next = NULL;sm_block_list.pFreeList[i].start_addr = NULL;for(j = 0; j < s_small_memory_num[i]; ++j){pSmNode pNew = pNodeAddr;++pNodeAddr;pNew->start_addr = (unsigned char*)firstAddr + count;pNew->next = NULL;count += s_small_memory_size[i];pTmp->next = pNew;pTmp = pNew;}sm_block_list.pBlockSize[i] = count - preCount;preCount = count;sm_block_list.pBlockFirstAddr[i] = sm_block_list.pFreeList[i].next->start_addr;}return;}void MemoryManage::SmlMemDeInit(){free(sm_block_list.pBlockSize);sm_block_list.pBlockSize = NULL;free(sm_block_list.pBlockFirstAddr);sm_block_list.pBlockFirstAddr = NULL;free(smlListFirstAddr);smlListFirstAddr = NULL;cout << "*************** SmlMemDeInit Success !!!*******************" << endl;}/* 获得小内存池第index 个的free 链表的节点    并将该节点标记为used, 转移到used 链表中去*/void* MemoryManage::GetFreeSmNode(int index){if(index >= total_small_list_head){cout << "invail index !!!!!!!!" << endl;return NULL;}int i = index;void* addr = sm_block_list.pFreeList[i].next->start_addr;pSmNode ptmp = sm_block_list.pFreeList[i].next;sm_block_list.pFreeList[i].next = sm_block_list.pFreeList[i].next->next;if(ptmp == sm_block_list.pUsedList[i].next){cout << "very fatal error!!!!  ptmp == sm_block_list.pUsedList[i].next" << endl;exit(-1);}ptmp->next = sm_block_list.pUsedList[i].next;sm_block_list.pUsedList[i].next = ptmp;return addr;}/* 将节点从used 链表转移到free 链表中去 */void MemoryManage::RetUsedSmNode(int index, void* addr){if(index >= total_small_list_head){cout << "invail index !!!!!!!!" << endl;return;}int i = index;pSmNode pCur = sm_block_list.pUsedList[i].next;pSmNode pPre = &sm_block_list.pUsedList[i];while(1){if(pCur == NULL)break;if(pCur->start_addr == addr)break;pPre = pCur;pCur = pCur->next;if(pPre == pCur){cout << "firstAddr = " << firstAddr << ", pCurAddr = " << pCur->start_addr << endl;exit(-1);}//cout << "free small memory find node, pCur = " << pCur << endl;}if(pCur != NULL){pPre->next = pCur->next;pCur->next = sm_block_list.pFreeList[i].next;sm_block_list.pFreeList[i].next = pCur;}else{cout << "i = " << i << " free small memory fail!!!!!" << endl;}return;}void* MemoryManage::MallocSmlMemory(size_t size){int i = 0; for(; i < total_small_list_head - 1; i++){if(size <= s_small_memory_size[i])break;}while(1){/* if this size free list have free node */if(sm_block_list.pFreeList[i].next != NULL){break;}else{  /* if this size free list doesn't have free node, then go to search big size free list */++i;if(i >= total_small_list_head - 1){  /* if all big size free list is used */cout << "small  freeList is FULL!!!!!!!!!!!" << endl;return NULL;}}}return GetFreeSmNode(i);}void MemoryManage::FreeSmlMemory(void *addr){int i = 0; for(; i < total_small_list_head - 1; i++){if((addr >= sm_block_list.pBlockFirstAddr[i]) && (addr < (unsigned char*)sm_block_list.pBlockFirstAddr[i] + sm_block_list.pBlockSize[i])){break;}}RetUsedSmNode(i, addr);return;}static MemoryManage mm_instance;void* myMalloc(size_t size){return mm_instance.Malloc(size);}void myFree(void* addr){mm_instance.Free(addr);return;}class D{public:D() : n(1), str("hello") { cout << "D() call" << endl; }~D();void* operator new(size_t size);     // operator new  设计自己分配内存的方式void operator delete(void *addr);void* operator new[](size_t size);void operator delete[](void *addr);void* operator new(size_t, void* addr); // placement new, 参数addr为已知的内存分配地址,设计调用构造函数初始化这个内存void operator delete(void* mem, void* addr);void setValue(int m) { n = m; }private:int n;string str;};D::~D(){cout << "~D() call" << endl;}void* D::operator new(size_t size){cout << "D::operator new call!!!, size = " << size << endl;return mm_instance.Malloc(size);}void D::operator delete(void *addr){cout << "D::operator delete call!!!" << endl;mm_instance.Free(addr);return;}void* D::operator new[](size_t size){cout << "D::operator new[] call!!!, size = " << size << endl;return mm_instance.Malloc(size);}void D::operator delete[](void *addr){cout << "D::operator delete[] call!!!" << endl;mm_instance.Free(addr);return;}void* D::operator new(size_t size, void* addr){cout << "D::operator placement new call!!!" << endl;::operator new(size, addr);return addr;}void D::operator delete(void* mem, void* addr){cout << "D::operator placement delete call!!!" << endl;::operator delete(mem);return;}/******************************************************/int main(){cout << sizeof(int) << endl;cout << sizeof(SmNode) << "," << sizeof(BigNode) << endl;cout << sizeof(st_SmBlockList) << "," << sizeof(st_BigBlockList) << endl;/*********************** memory magement test********************************/clock_t start = clock();int l = 0;for(l = 0; l < 100000; l++){/*  my memory management */int *ar = (int*)myMalloc(sizeof(int) * 10);if(ar == NULL)cout << "myMalloc ar fail!!!" << endl;myFree(ar);}float end = float(clock() - start)/CLOCKS_PER_SEC;cout << "(1) time is " << end << "seconds." << endl;   // 0.028 sstart = clock();for(l = 0; l < 100000; l++){/*  my memory management */int *ar = (int*)malloc(sizeof(int) * 10);if(ar == NULL)cout << "malloc fail!!!" << endl;free(ar);}end = float(clock() - start)/CLOCKS_PER_SEC;cout << "(2) time is " << end << "seconds." << endl;  // 0.032 s/* 测试随机分配 随机释放内存 100万次 */char* parr[1024] = {NULL};srand(time(NULL));start = clock();int failcount = 0;for(l = 0; l < 1000000; l++){static unsigned int i = 0;int rand_index = 0;rand_index = rand() % 1024;int rand_size = rand() % 5120 + 1025;rand_size &= (~3);rand_size += 4;char *ai = (char*)myMalloc(sizeof(char) * rand_size);if(!ai){cout << "(1) malloc ai fail!!!" << endl;#if 1pBigNode b = mm_instance.GetBigListHead()->next;int unUsed = 0;int total = 0;while(b->next != NULL){if(b->usedFlag == 0)unUsed++;b = b->next;++total;}cout << "total count = " << total << " unUsed count = " << unUsed << endl;#endiffailcount++;}if(parr[rand_index] != NULL){myFree(parr[rand_index]);parr[rand_index] = NULL;}parr[rand_index] = ai;++i;if(i % 1000 == 0){//cout << i << endl;}if(i >= 0xffffffff)i = 0;rand_index = rand() % 1024;myFree(parr[rand_index]);parr[rand_index] = NULL;}end = float(clock() - start)/CLOCKS_PER_SEC;cout << "(3) time is " << end << "seconds." << endl;  // 2.768 scout << "Fail NUM: " << failcount << endl;for(l = 0; l < 1024; l++){if(parr[l] != NULL){myFree(parr[l]);parr[l] = NULL;}}start = clock();for(l = 0; l < 1000000; l++){static unsigned int i = 0;int rand_index = 0;rand_index = rand() % 1024;int rand_size = rand() % 5120 + 1025;rand_size &= (~3);rand_size += 4;char *ai = (char*)malloc(sizeof(char) * rand_size);if(!ai){cout << "(1) malloc ai fail!!!; SIZE = " << rand_size << endl;}if(parr[rand_index] != NULL){free(parr[rand_index]);parr[rand_index] = NULL;}parr[rand_index] = ai;++i;if(i % 1000 == 0){//cout << i << endl;}if(i >= 0xffffffff)i = 0;rand_index = rand() % 1024;free(parr[rand_index]);parr[rand_index] = NULL;}end = float(clock() - start)/CLOCKS_PER_SEC;cout << "(4) time is " << end << "seconds." << endl;  // 0.746 schar* ptmp = (char*)myMalloc(sizeof(char) * 960 * 540);myFree(ptmp);ptmp = NULL;/* operator new 和 delete 的重载 */D *dp = new D;delete dp;void *ddp = malloc(sizeof(D));D *dvp = new (ddp) D; //调用placement new 在已获得的内存空间中构造一个D对象dvp->~D();D *dap = new D[10];dap[3].setValue(100);delete [] dap;return 0;}

0 0
原创粉丝点击