1.c++实现一个不能被继承的类
一般我们都会把构造函数,析构函数设置为private,仿照单例模式来设计。
class class1
{
public:
static class1 * getinstance(){
return new class1();
}
static void deleteInstance(class1 *pInstace){
delete pInstace;
}
private:
class1(){};
~class1(){};
}
但是在上面模式中,得到的实例都是在堆上,需要我们自己来释放,或者调用对应的函数。
考虑到这一局限,我们可以设计如下的一个类
template <typename T>
class MakeFinal
{
friend T;
private:
MakeFinal(){};
~MakeFinal(){};
}
class FinalClass2 : virtual public MakeFinal<FinalClass2>
{
public:
FinalClass2(){};
~FinalClass2(){};
}
因为是友元类的关系,FinalClass2 可以调用MakeFinal的构造及析构函数
到那时继承自FinalClass2的类,如果要实例化,因为FinalClass2是虚继承,会跳过FinalClass2,而是直接调用MakeFinal的构造函数.但是此时已经
不可以调用MakeFinal的构造函数了。会导致编译错误.
2.如何自定义函数检测内存泄漏
gcc允许为函数设置__attribute__ ((constructor))和__attribute__ ((destructor))两种属性,顾名思义,就是将被修饰的函数作为构造函数或析构函数。
程序员可以通过类似下面的方式为函数设置这些属性:
void funcBeforeMain() __attribute__ ((constructor));
void funcAfterMain() __attribute__ ((destructor));
也可以放在函数名之前:
void __attribute__ ((constructor)) funcBeforeMain();
void __attribute__ ((destructor)) funcAfterMain();
带有(constructor)属性的函数将在main()函数之前被执行,而带有(destructor)属性的函数将在main()退出时执行。
leak_detector.h
#ifndef LEAK_DETECTOR_C_H
#define LEAK_DETECTOR_C_H
#pragma (report_mem_leak)
#define FILE_NAME_LENGTH 256 //用于存储malloc被调用的所在的文件名
#define CALL_DEPTH 10 //最大调用深度
#define TIME_LEN 26 //日期字符串的长度
#define OUTPUT_FILE "leak_info.txt" // 存储内存泄漏信息
#define malloc(size) mymalloc(size, __FILE__,__LINE__)
#define calloc(elements, size) mycalloc(elements ,__FILE__,__LINE__)
#define realloc (address, size) myrealloc(address, size, __FILE__,__LINE__)
#define free(mem_ref) myfree(mem_ref)
struct _MEM_TRACE_INFO{
char ** traceInfo;
size_t size;
};
typedef struct _MEM_TRACE_INFO MEM_TRACE_INFO;
struct _MEM_INFO{
void *address ;
unsigned int size ;
char file_name[FILE_NAME_LENGTH];
unsigned int line ;
char allocTime[TIME_LEN];
MEM_TRACE_INFO * traceInfo;
};
typedef struct _MEM_INFO MEM_INFO;
struct _MEM_LEAK {
MEM_INFO mem_info;
struct _MEM_LEAK *next;
};
typedef struct _MEM_LEAK MEM_LEAK;
static void add(MEM_INFO alloc_info);
static void erase(void * address);
static void clear(void);
void *mymalloc(unsigned int, const char* ,unsigned int );
void *mycalloc(unsigned int ,unsigned int , const char* ,unsigned int );
void *myrealloc(void *,unsigned int , const char* ,unsigned int );
void *myfree( void * mem_ref);
static void add_mem_info(void*, unsigned int , const char* ,unsigned int , MEM_TRACE_INFO*);
static void remove_mem_info(void *mem_ref);
void report_mem_lead(void) __attribute__((destructor));
#endif
leak_detector.c
注意一下
- #undef malloc
- #undef calloc
- #undef realloc
- #undef free
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <time.h>
#include <execinfo.h>
#undef malloc
#undef calloc
#undef realloc
#undef free
static MEM_LEAK *ptr_start = NULL;
static MEM_LEAK *ptr_end = NULL;
MEM_TRACE_INFO * getTrackInfo(){
void * array[CALL_DEPTH];
size_t size;
size = backtrace(array,10);
char ** trace = backtrace_symbols(array,size);
MEM_TRACE_INFO * traceInfo = (MEM_TRACE_INFO *) malloc( sizeof(MEM_TRACE_INFO ));
if(traceInfo == NULL){
return NULL;
}
traceInfo ->size = size;
traceInfo ->traceInfo = trace;
return traceInfo;
}
void add(MEM_INFO alloc_info)
{
printf("add new allocation info:%d\n", alloc_info.address);
MEM_LEAK* mem_leak_info =NULL;
mem_leak_info=(MEM_LEAK*) malloc(sizeof(MEM_LEAK));
mem_leak_info->mem_info.address = alloc_info.address;
mem_leak_info->mem_info.size = alloc_info.size;
strcpy(mem_leak_info->mem_info.file_name,alloc_info.file_name);
mem_leak_info->mem_info.line=alloc_info.line;
mem_leak_info->mem_info.traceInfo= alloc_info.traceInfo;
strncpy(mem_leak_info->mem_info.allocTime,alloc_info.allocTime,TIME_LEN);
if(ptr_start == NULL){
ptr_start = mem_leak_info;
ptr_end = ptr_start ;
}else{
ptr_end->next = mem_leak_info;
ptr_end = ptr_end->next;
}
}
void erase(void * address)
{
MEM_LEAK *temp = ptr_start ;
MEM_LEAK *pre;
if(temp != NULL && temp->mem_info.address == address){
ptr_start = temp->next;
free(temp->mem_info.traceInfo);
free(temp);
return;
}
if(temp->next != NULL){
pre = temp;
temp = temp->next;
for(; temp!= NULL; pre= temp,temp=temp->next)
{
if(temp->mem_info.address == address)
{
pre->next = temp ->next;
if(temp->next == NULL)
ptr_end = pre;
free(temp->mem_info.traceInfo);
free(temp);
break;
}
}
}
}
void clear(){
MEM_LEAK *temp = ptr_start;
MEM_LEAK* alloc_info = ptr_start ;
while(alloc_info != NULL)
{
alloc_info = alloc_info->next;
free(temp->mem_info.traceInfo);
free(temp);
temp=alloc_info;
}
}
void *mymalloc(unsigned int size , const char* file ,unsigned int line)
{
void *ptr = malloc(size);
if(ptr != NULL){
MEM_TRACE_INFO *traceinfo = getTrackInfo();
add_mem_info(ptr,size,file,line,traceinfo);
}
return ptr;
}
void *mycalloc(unsigned int elements ,unsigned int size , const char* file,unsigned int line)
{
printf("calloc\n");
unsigned total_size;
void *ptr = calloc(elements,size);
if(ptr != NULL)
{
MEM_TRACE_INFO* traceinfo = getTrackInfo();
total_size = elements *size;
add_mem_info(ptr,total_size,file,line,traceinfo);
}
}
void *myrealloc(void * address ,unsigned int size , const char* file,unsigned int line)
{
printf("realloc\n");
unsigned total_size;
void *ptr = realloc(address,size);
if(ptr != NULL)
{
MEM_TRACE_INFO* traceinfo = getTrackInfo();
remove_mem_info(address);
add_mem_info(address,size,file,line,traceinfo);
}
}
void *myfree( void * mem_ref)
{
remove_mem_info(mem_ref);
free(mem_ref);
}
void add_mem_info(void* mem_ref, unsigned int size, const char*file ,unsigned int line , MEM_TRACE_INFO* traceinfo)
{
MEM_INFO mem_alloc_info;
memset(&mem_alloc_info ,0 ,sizeof(mem_alloc_info));
mem_alloc_info.address = mem_ref;
mem_alloc_info.size = size;
strcpy(mem_alloc_info.file_name, file);
mem_alloc_info.line = line ;
mem_alloc_info.traceInfo = traceinfo;
time_t timeP = time(0);
char* t = ctime(&timeP);
strncpy(mem_alloc_info.allocTime ,t ,TIME_LEN);
add(mem_alloc_info);
}
void remove_mem_info(void *mem_ref){
erase(mem_ref);
}
void report_mem_lead(void) {
unsigned int i ;
printf("%s","mem_leak");
unsigned short index ;
MEM_LEAK * leak_info;
FILE* fp_write = fopen(OUTPUT_FILE , "w");
char info[1024];
if( fp_write != NULL)
{
fprintf(fp_write ,"%s\n", "Memory Leak Summary");
fprintf(fp_write ,"%s\n", "----------------------------------------");
for( leak_info = ptr_start ; leak_info != NULL; leak_info = leak_info ->next)
{
fprintf(fp_write ,"address:%x\n",leak_info->mem_info.address);
fprintf(fp_write ,"size :%d bytes\n",leak_info->mem_info.size);
fprintf(fp_write ,"file :%s\n",leak_info->mem_info.file_name);
fprintf(fp_write ,"line :%d\n",leak_info->mem_info.line);
fprintf(fp_write ,"Time :%s\n",leak_info->mem_info.allocTime);
fprintf(fp_write ,"traceInfo :\n");
for(i = 2 ;i < leak_info->mem_info.traceInfo->size-2;i++)
{
fprintf(fp_write ,"%s\n",leak_info->mem_info.traceInfo->traceInfo[i]);
}
fprintf(fp_write ,"%s\n","----------------------------------------");
}
}
clear();
}
test.c
#include <stdio.h>
#include "leak_detector.h"
int main()
{
char *p = NULL;
p = (char*)malloc(4);
free(p);
p = (char*)malloc(5);
p = (char*)malloc(6);
return 0 ;
}
makefile
test:test.c leak_detector.h leak.so
gcc -o test test.c ./leak.so -rdynamic
leak.so:leak_detector.o
gcc -shared -o leak.so leak_detector.o -rdynamic
leak_detector.o:leak_detector.h leak_detector.c
gcc -fpic -c leak_detector.c -rdynamic
clean:
rm *.so *.o
检测结果如下:
Memory Leak Summary
----------------------------------------
address:14b6010
size :5 bytes
file :test.c
line :12
Time :Wed Jul 18 23:31:59 2018
traceInfo :
./test(main+0x48) [0x400785]
----------------------------------------
address:14b6a60
size :6 bytes
file :test.c
line :14
Time :Wed Jul 18 23:31:59 2018
traceInfo :
./test(main+0x60) [0x40079d]
----------------------------------------
扫描关注我
(转载本站文章请注明作者和出处 Undefined)