之所以单独写这一章是因为发现了两个非常好用的保留字__FILE__和__LINE__。而C++编程思想把这两个关键字用在查找内存泄漏上,我觉得非常管用。
从用的手段上来说,是用自定义的宏代替关键字。这并称为Dark Technique。但是不管黑猫白猫,能抓住老鼠的就是好猫。用了C++编程思想用用于测试的代码内存泄漏的代码,觉得非常好用。但是还有一定的遗憾。这仅仅适用于new的内存,广义的内存泄漏,如句柄泄漏,Socket等资源的泄漏,这就无能为力了。不过这已经很不错了。
下面全文转载了《C++编程思想》的程序源码:
//: C02:MemCheck.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef MEMCHECK_H
#define MEMCHECK_H
#include <cstddef> // For size_t
// Usurp the new operator (both scalar and array versions)
void* operator new(std::size_t, const char*, long);
void* operator new[](std::size_t, const char*, long);
#define new new (__FILE__, __LINE__)
extern bool traceFlag;
#define TRACE_ON() traceFlag = true
#define TRACE_OFF() traceFlag = false
extern bool activeFlag;
#define MEM_ON() activeFlag = true
#define MEM_OFF() activeFlag = false
#endif // MEMCHECK_H ///:~
//: C02:MemCheck.cpp {O}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstddef>
using namespace std;
#undef new
// Global flags set by macros in MemCheck.h
bool traceFlag = true;
bool activeFlag = false;
namespace {
// Memory map entry type
struct Info {
void* ptr;
const char* file;
long line;
};
// Memory map data
const size_t MAXPTRS = 10000u;
Info memMap[MAXPTRS];
size_t nptrs = 0;
// Searches the map for an address
int findPtr(void* p) {
for(size_t i = 0; i < nptrs; ++i)
if(memMap[i].ptr == p)
return i;
return -1;
}
void delPtr(void* p) {
int pos = findPtr(p);
assert(pos >= 0);
// Remove pointer from map
for(size_t i = pos; i < nptrs-1; ++i)
memMap[i] = memMap[i+1];
--nptrs;
}
// Dummy type for static destructor
struct Sentinel {
~Sentinel() {
if(nptrs > 0) {
printf("Leaked memory at:/n");
for(size_t i = 0; i < nptrs; ++i)
printf("/t%p (file: %s, line %ld)/n",
memMap[i].ptr, memMap[i].file, memMap[i].line);
}
else
printf("No user memory leaks!/n");
}
};
// Static dummy object
Sentinel s;
} // End anonymous namespace
// Overload scalar new
void*
operator new(size_t siz, const char* file, long line) {
void* p = malloc(siz);
if(activeFlag) {
if(nptrs == MAXPTRS) {
printf("memory map too small (increase MAXPTRS)/n");
exit(1);
}
memMap[nptrs].ptr = p;
memMap[nptrs].file = file;
memMap[nptrs].line = line;
++nptrs;
}
if(traceFlag) {
printf("Allocated %u bytes at address %p ", siz, p);
printf("(file: %s, line: %ld)/n", file, line);
}
return p;
}
// Overload array new
void*
operator new[](size_t siz, const char* file, long line) {
return operator new(siz, file, line);
}
// Override scalar delete
void operator delete(void* p) {
if(findPtr(p) >= 0) {
free(p);
assert(nptrs > 0);
delPtr(p);
if(traceFlag)
printf("Deleted memory at address %p/n", p);
}
else if(!p && activeFlag)
printf("Attempt to delete unknown pointer: %p/n", p);
}
// Override array delete
void operator delete[](void* p) {
operator delete(p);
} ///:~