C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_memory_leak_detect.hpp
Go to the documentation of this file.
1/* Programmed by: Thomas Kim
2
3 First Created: Nov. 5, 2017
4 Last Modified: Nov. 7, 2017
5
6 Version: 1.2
7*/
8
9#ifndef TPF_MEMORY_LEAK_DETECT_HPP
10#define TPF_MEMORY_LEAK_DETECT_HPP
11
12#ifndef NOMINMAX
13#define NOMINMAX
14#endif
15
16#include <iostream>
17#include <sstream>
18#include <string>
19
20#ifndef _WINDOWS_
21 #include <atlstr.h>
22#endif
23
24#ifdef UNICODE
25 #define STDSTRING std::wstring
26 #define STRSTREAM std::wostringstream
27 #define UNISTR(txt) L##txt
28 #define UNITXT(txt) UNISTR(#txt)
29 #define STDCOUT std::wcout
30#else
31 #define STDSTRING std::string
32 #define STRSTREAM std::ostringstream
33 #define UNISTR(txt) txt
34 #define UNITXT(txt) UNISTR(#txt)
35 #define STDCOUT std::cout
36#endif
37
38#if !defined(_WINDOWS) && !defined(_AFXDLL)
39
40 #ifdef _DEBUG
41 // order of #define
42 // and #include should be preserved
43 #define _CRTDBG_MAP_ALLOC
44 #include <cstdlib>
45 #include <crtdbg.h>
46
47 #ifndef new
48 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
49 #endif
50
51 class CMemLeakCheck
52 {
53 protected:
54 STDSTRING m_filename;
55 STDSTRING m_varname;
56 int m_lineno;
57 size_t m_total;
58
59 public:
60 CMemLeakCheck(const STDSTRING& filename=UNISTR(""),
61 int lineno=0, const STDSTRING& varname=UNISTR("")) :
62 m_filename(filename), m_lineno(lineno), m_varname(varname), m_total(0)
63 {
64 // does not work
65 Reset();
66 }
67
68 void Reset() {
69
70 _CrtMemState mem_state;
71 _CrtMemCheckpoint(&mem_state);
72 this->m_total = mem_state.lSizes[_NORMAL_BLOCK];
73 }
74
75 size_t Difference() {
76
77 _CrtMemState mem_state;
78 _CrtMemCheckpoint(&mem_state);
79
80 return mem_state.lSizes[_NORMAL_BLOCK] - this->m_total;
81 }
82
83 STDSTRING Message(int lineno = 0, bool from_destructor=false)
84 {
85 size_t bytes = Difference();
86
87 STRSTREAM stm;
88
89 if (bytes > 0)
90 {
91 stm << UNISTR("File: ") << m_filename << UNISTR("\nAt line: ") << (lineno ? lineno : m_lineno)
92 << UNISTR(", Checkpoint: ") << m_varname << UNISTR(", ") << bytes
93 << (from_destructor ? UNISTR(" bytes LEAKED.") : UNISTR(" bytes ALIVE."));
94 }
95 else
96 {
97 stm << UNISTR("Memory State CLEAN.");
98 }
99
100 return stm.str();
101 }
102
103 void Report(int lineno = 0, bool from_destructor=false)
104 {
105 STDCOUT << UNISTR("\n") << Message(lineno, from_destructor) << UNISTR("\n");
106 }
107
108 ~CMemLeakCheck()
109 {
110 if (Difference() > 0) { Report(0, true); }
111 }
112 };
113
114
115 #define MemLeakCheckReport(varname) varname.Report(__LINE__)
116 #define MemLeakCheckMessage(varname) varname.Message(__LINE__)
117
118 #endif // end of debugging
119
120
121#else // MFC Console or MFC Window
122
123 #ifdef _DEBUG
124
125 #ifndef new
126 #define new DEBUG_NEW
127 #endif
128
129 class CMemLeakCheck
130 {
131 protected:
132 CString m_filename;
133 CString m_varname;
134 int m_lineno;
135 size_t m_total;
136
137 CMemoryState mem_state;
138
139 public:
140 CMemLeakCheck(const CString& filename= UNISTR(""),
141 int lineno=0, const CString& varname= UNISTR("")) :
142 m_filename(filename), m_lineno(lineno), m_varname(varname), m_total(0)
143 {
144 // this does not work
145 // Reset();
146 }
147
148 void Reset()
149 {
150 mem_state.Checkpoint();
151 this->m_total = mem_state.m_lSizes[_NORMAL_BLOCK];
152 }
153
154 size_t Difference()
155 {
156 mem_state.Checkpoint();
157 return (mem_state.m_lSizes[_NORMAL_BLOCK]) - this->m_total;
158 }
159
160 #ifdef _CONSOLE
161 STDSTRING
162 #else
163 CString
164 #endif
165 Message(int lineno=0, bool from_destructor=false)
166 {
167 size_t bytes = Difference();
168
169 STRSTREAM stm;
170
171 if (bytes > 0)
172 {
173
174 stm << UNISTR("File: ") << m_filename.GetString() << UNISTR("\nAt line: ") << (lineno ? lineno : m_lineno)
175 << UNISTR(", Checkpoint: ") << m_varname.GetString() << UNISTR(", ") << bytes <<
176 (from_destructor ? UNISTR(" bytes LEAKED.") : UNISTR(" bytes are ALIVE."));
177 }
178 else
179 {
180 stm << UNISTR("Memory Clean.");
181 }
182
183 #ifdef _CONSOLE
184
185 return stm.str();
186
187 #else
188
189 return CString(stm.str().c_str());
190 #endif
191 }
192
193 void Report(int lineno = 0, bool from_destructor=false)
194 {
195 #ifdef _CONSOLE
196 STDCOUT <<std::endl<<Message(lineno, from_destructor) << std::endl;
197
198 #else
199 CString msg = Message(lineno, from_destructor);
200 AfxMessageBox(msg);
201 #endif
202 }
203
204 ~CMemLeakCheck()
205 {
206 if (Difference() > 0) { Report(0, true); }
207 }
208 };
209
210 #define MemLeakCheckReport(varname) varname.Report(__LINE__)
211 #define MemLeakCheckMessage(varname) varname.Message(__LINE__)
212
213 //#define MemLeakCheckReport(varname) AfxMessageBox(_T("MemLeakCheckReport is not supported in MFC Windows App"))
214 //#define MemLeakCheckMessage(varname) AfxMessageBox(_T("MemLeakCheckMessage is not supported in MFC Windows App"))
215
216 #endif // end of debugging
217#endif //
218
219#ifdef _DEBUG
220
221 #ifdef UNICODE
222 #define Tpf_MemLeakCheck(varname) CMemLeakCheck varname(__FILEW__, __LINE__, UNITXT(varname)) ; varname.Reset()
223 #else
224 #define Tpf_MemLeakCheck(varname) CMemLeakCheck varname(__FILE__, __LINE__, UNITXT(varname)) ; varname.Reset()
225 #endif
226
227 #define Tpf_MemLeakCheckReport(varname) varname.Report(__LINE__)
228 #define Tpf_MemLeakCheckMessage(varname) varname.Message(__LINE__)
229#else
230 // non debugging mode
231 #define Tpf_MemLeakCheck(varname)
232 #define Tpf_MemLeakCheckReport(varname)
233 #define Tpf_MemLeakCheckMessage(varname)
234#endif
235
236#endif // end of file
auto & endl
#define STDSTRING
#define STRSTREAM
#define UNISTR(txt)
#define STDCOUT