fs/sys/fsMemMgr.cpp

Go to the documentation of this file.
00001 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00002 /*                          _______      ______    ______          __      */
00003 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~    / ____(_)___ / ___ /)  / ____/___  ____/ /__    */
00004 /*      [fsMemMgr]        / /_  / / __ \\__ \|/  / /   / __ \/ __  / _ \   */
00005 /*       rev. 24         / __/ / / /_/ /__/ /   / /___/ /_/ / /_/ /  __/   */
00006 /*    20th Jan 2007     /_/   /_/ ,___/____/    \____/\____/\__,_/\___/    */
00007 /*     [x] stable              /_/ (c) 2005-7 Filip STOKLAS (FipS)         */
00008 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~       http://HOLE.4FipS.com/fips_code.php          */
00009 /*                                                                         */
00010 /* This code is free for personal and commercial use. You may redistribute */
00011 /* it by any means. If you use the code for your own projects please give  */
00012 /* me credit. Please send a bug report. Don't alter or remove this header! */
00013 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00014 // NOTES:
00015 // [o] Dependency reduction design compromises:
00016 //     [o] 'std::allocator<void>::const_pointer' => 'const void *'
00017 //     [o] 'std::numeric_limits<size_type>::max()' => 'size_t(-1)'
00018 // [o] Workaround for Pocket PC 2002 env.: old SGI STL & MS eVC++ 6.0
00019 //     [o] FS_MMGR_WORKAROUND1 defined
00020 //     [o] nonstandard custom allocator
00021 //     [o] 'Key_t' things...
00022 //---------------------------------------------------------------------------
00023 #include <fs/sys/fsMemMgr.h>
00024 
00025 #include <fs/sys/fsMemMgr_NoT.h> // turn off the tracking macros
00026 #include <memory>
00027 #include <map>
00028 #include <fs/sys/fsMemMgr.h> // turn on the tracking macros
00029 
00030 #if defined(UNDER_CE)
00031 #   include<windows.h> // TerminateProcess
00032 #endif
00033 //---------------------------------------------------------------------------
00034 #if (_MSC_VER >= 1400) // MSVC8
00035 #   pragma warning(disable : 4996) // function was marked as deprecated
00036 #endif
00037 //---------------------------------------------------------------------------
00038 #if defined(UNDER_CE) && defined(__STL_DEFAULT_ALLOCATOR)
00039 #   define FS_MMGR_WORKAROUND1
00040 #endif
00041 //---------------------------------------------------------------------------
00042 #if defined(FS_MMGR_ENABLE_BASIC_STATS) || defined(FS_MMGR_ENABLE_TRACKING)
00043 #   define FS_MMGR_DEF_ATEXIT
00044 #endif
00045 //---------------------------------------------------------------------------
00046 // Define a 'silent' assert break with no memory allocations.
00047 #if defined(FS_MMGR_ENABLE_TRACKING) && defined(FS_MMGR_ENABLE_RTM_BREAK)
00048 #   if defined(_WIN32)
00049 #       if defined(UNDER_CE)
00050 #           define FS_MMGR_ASSERT(exp)                                      \
00051             {                                                               \
00052                 bool bExp = (exp) ? true : false;                           \
00053                 if(!bExp) TerminateProcess(GetCurrentProcess(), 0);         \
00054             }
00055 #       else
00056 #           define FS_MMGR_ASSERT(exp)                                      \
00057             {                                                               \
00058                 bool bExp = (exp) ? true : false; if(!bExp) __asm int 3     \
00059             }
00060 #       endif
00061 #   else
00062 #       define FS_MMGR_ASSERT(exp) (void(0))
00063 #   endif
00064 #else
00065 #   define FS_MMGR_ASSERT(exp) (void(0))
00066 #endif
00067 //---------------------------------------------------------------------------
00068 //--- ANONYMOUS NAMESPACE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00069 //---------------------------------------------------------------------------
00070 namespace {
00071 //---------------------------------------------------------------------------
00072 const char *GetModNm();
00073 //---------------------------------------------------------------------------
00075 char g_szModNm[32] = {'\0'};
00076 //---------------------------------------------------------------------------
00077 #if defined(FS_MMGR_DEF_ATEXIT)
00079 bool g_bAtExitSet = false;
00080 #endif
00081 //---------------------------------------------------------------------------
00082 #if defined(FS_MMGR_ENABLE_BASIC_STATS)
00084 class Stats_t
00085 {
00086  public:
00087  
00088     Stats_t() : m_nAlloc(0), m_nFree(0), m_nMax(0) {}
00089      
00090     void Alloc()
00091     {
00092         ++m_nAlloc;
00093         
00094         // update the maximum number of allocations
00095         const int nDelta = m_nAlloc - m_nFree;
00096         if(nDelta > m_nMax) m_nMax = nDelta;
00097     }
00098     
00099     void Free() { ++m_nFree; }
00100     
00101     int GetNumLeaks() const { return m_nAlloc - m_nFree; }
00102     
00103     void Dump(FILE *hOut) const
00104     {
00105         int nLeaks = GetNumLeaks();
00106     
00107         ::fprintf(hOut, "+--------------------------------------------+\n");
00108         ::fprintf(hOut, "| FipS' MEMORY MANAGER (basic stats)         |\n");
00109         ::fprintf(hOut, "| module: %-34s |\n", GetModNm());
00110         ::fprintf(hOut, "+--------------------------------+-----------+\n");
00111         ::fprintf(hOut, "|    Total number of allocations | %-9d |\n",
00112          m_nAlloc);
00113         ::fprintf(hOut, "|  Total number of deallocations | %-9d |\n",
00114          m_nFree);
00115         ::fprintf(hOut, "|      Max number of allocations | %-9d |\n",
00116          m_nMax);
00117         ::fprintf(hOut, "|                Number of leaks | %-7d %c |\n",
00118          nLeaks, nLeaks > 0 ? '!' : ' ' );
00119         ::fprintf(hOut, "+--------------------------------+-----------+\n");
00120     }
00121     
00122  private:
00123  
00124     int m_nAlloc;
00125     int m_nFree;
00126     int m_nMax;
00127     
00128 } g_Stats;
00129 #endif
00130 //---------------------------------------------------------------------------
00131 #if defined(FS_MMGR_ENABLE_TRACKING)
00133 enum MemOp_e
00134 {
00135     MOP_NEW,
00136     MOP_DELETE,
00137     MOP_NEW_ARRAY,
00138     MOP_DELETE_ARRAY
00139 };
00140 #endif
00141 //---------------------------------------------------------------------------
00142 #if defined(FS_MMGR_ENABLE_TRACKING)
00144 const char * const apszMemOpNms[] =
00145 {
00146     "new",
00147     "delete",
00148     "new []",
00149     "delete []"
00150 };
00151 #endif
00152 //---------------------------------------------------------------------------
00153 #if defined(FS_MMGR_ENABLE_TRACKING)
00155 const MemOp_e aMemOpPrs[][2] = 
00156 {
00157     { MOP_NEW,       MOP_DELETE },
00158     { MOP_NEW_ARRAY, MOP_DELETE_ARRAY }
00159 };
00160 #endif
00161 //---------------------------------------------------------------------------
00162 #if defined(FS_MMGR_ENABLE_TRACKING)
00164 void StrCpyCrp(char *pszDest, const char *pszSrc, size_t uMaxLen)
00165 {
00166     size_t uLen = ::strlen(pszSrc);
00167             
00168     if(uLen > uMaxLen)
00169     {
00170         size_t uCount = uMaxLen - 2;
00171         pszDest[0] = pszDest[1] = pszDest[2] = '.';
00172         ::memcpy(pszDest + 3, pszSrc + uLen - uCount + 1, uCount);
00173     }
00174     else
00175         ::strcpy(pszDest, pszSrc);
00176     
00177 }
00178 #endif
00179 //---------------------------------------------------------------------------
00180 #if defined(FS_MMGR_ENABLE_TRACKING)
00182 class CodePos_t
00183 {
00184  public:
00185 
00186     char m_szFunc[32];
00187     char m_szFile[32];
00188     int  m_nLine;
00189         
00190     CodePos_t() { m_szFunc[0] = m_szFile[0] = '?'; m_szFunc[1] =
00191      m_szFile[1] = '\0'; m_nLine = -1; }
00192      
00193     CodePos_t(const char *pszFunc, const char *pszFile, int nLine)
00194     {
00195         *this = CodePos_t(); // reset the state
00196         
00197         if(pszFunc) StrCpyCrp(m_szFunc, pszFunc, sizeof(m_szFunc) - 1);
00198         if(pszFile) StrCpyCrp(m_szFile, pszFile, sizeof(m_szFile) - 1);
00199         
00200         m_nLine = nLine;
00201     }
00202     
00203 } g_LastPos;
00204 #endif
00205 //---------------------------------------------------------------------------
00206 #if defined(FS_MMGR_ENABLE_TRACKING)
00207 #pragma warning(push)
00208 #pragma warning(disable: 4100) // unreferenced formal parameter
00209 //---
00210 // It is necessary to provide a custom STL memory allocator in order to
00211 // prevent recursion during internal (de)allocations.
00212 //---
00213 #if defined(FS_MMGR_WORKAROUND1)
00214 //---
00215 template<class T>
00216 class Alloc_T // the simplified SGI's allocator interface
00217 {
00218  public:
00219 
00220     // call the global malloc / free
00221     static T* allocate(size_t n)
00222      { return reinterpret_cast<T*>(::malloc(n * sizeof(T))); }
00223     static T* allocate(void)
00224      { return reinterpret_cast<T*>(::malloc(sizeof(T))); }
00225     static void deallocate(void *p, size_t n)
00226      { ::free(p); }
00227     static void deallocate(void *p)
00228      { ::free(p); }
00229 };
00230 //---
00231 #else
00232 //---
00233 template <class T>
00234 class Alloc_T // the standard allocator interface
00235 {
00236  public:
00237  
00238     typedef T value_type;
00239     typedef T* pointer;
00240     typedef const T* const_pointer;
00241     typedef T& reference;
00242     typedef const T& const_reference;
00243     typedef size_t size_type;
00244     typedef ptrdiff_t difference_type;
00245     
00246     template <class U>
00247     struct rebind { typedef Alloc_T<U> other; };
00248     
00249     Alloc_T() {}
00250     Alloc_T(const Alloc_T &) {}
00251 #if !defined(_MSC_VER) || _MSC_VER >= 1300 
00252     template <class U>
00253     Alloc_T(const Alloc_T<U> &) {}
00254 #endif
00255     ~Alloc_T() {}
00256         
00257     pointer address(reference r) const { return &r; }
00258     const_pointer address(const_reference r) const { return &r; }
00259             
00260     // call the global malloc / free
00261     pointer allocate(size_type n, const void * = 0)
00262      { return reinterpret_cast<pointer>(::malloc(n * sizeof(T))); }
00263     void deallocate(pointer p, size_type) { ::free(p); }
00264             
00265     size_type max_size() const { return size_t(-1) / sizeof(T); }
00266             
00267     void construct(pointer p, const T &t) { new(p) T(t); }
00268     void destroy(pointer p) { p->~T(); }
00269 };
00270 //---
00271 template <class T, class U>
00272 bool operator == (const Alloc_T<T> &, const Alloc_T<U> &)
00273 { return true; }
00274 //---
00275 template <class T, class U>
00276 bool operator != (const Alloc_T<T> &LHS, const Alloc_T<U> &RHS)
00277 { return false; }
00278 //---
00279 template <>
00280 class Alloc_T<void>
00281 {
00282  public:
00283     
00284     typedef void value_type;
00285     typedef void* pointer;
00286     typedef const void* const_pointer;
00287     typedef size_t size_type;
00288     typedef ptrdiff_t difference_type;
00289     
00290     template <class U>
00291     struct rebind { typedef Alloc_T<U> other; };
00292 };
00293 //---
00294 #endif
00295 //---
00296 #pragma warning(pop)
00297 #endif
00298 //---------------------------------------------------------------------------
00299 #if defined(FS_MMGR_ENABLE_TRACKING)
00301 class Tracker_t
00302 {
00303  public:
00304  
00305     Tracker_t() : m_nCurMem(0), m_nMaxMem(0) {}
00306  
00307     void Alloc(const void *pAddr, int nSize, MemOp_e eMemOp,
00308      const CodePos_t &Pos)
00309     {
00310         FS_MMGR_ASSERT(pAddr);
00311 
00312         Val_t Val(nSize, eMemOp, Pos);
00313         m_Map.insert(Pair_t(pAddr, Val));
00314         m_nCurMem += nSize;
00315         
00316         // update the maximum amount of used memory
00317         if(m_nCurMem > m_nMaxMem) m_nMaxMem = m_nCurMem;
00318         
00319         g_LastPos = CodePos_t(); // reset the last code position
00320     }
00321 
00322     void Free(const void *pAddr, MemOp_e eMemOp)
00323     {
00324         if(!pAddr) // according to the standard it is correct
00325             return;
00326             
00327         Map_t::iterator it = m_Map.find(pAddr);
00328 
00329         if(it == m_Map.end())
00330         {
00331             //     RUNTIME ERROR: An unknown / bad memory address 'pAddr'
00332             //                    has been passed!
00333             FS_MMGR_ASSERT(0); // ^^^
00334             return;
00335         }
00336 
00337         MemOp_e AllocMemOp = (*it).second.m_MemOp;
00338         bool bFound = false;
00339         for(int i = 0; i < sizeof(aMemOpPrs) / sizeof(aMemOpPrs[0]); ++i)
00340             if(
00341              AllocMemOp == aMemOpPrs[i][0] &&
00342              eMemOp == aMemOpPrs[i][1]
00343             )
00344                 { bFound = true; break; }
00345             
00346         if(!bFound)
00347         {
00348             //     RUNTIME ERROR: Wrong deallocation method detected!
00349             //                    (see 'AllocMemOp' vs. 'FreeMemOp')
00350             FS_MMGR_ASSERT(0); // ^^^
00351             return;
00352         }
00353         
00354         m_nCurMem -= (*it).second.m_nSize;
00355         m_Map.erase(it);
00356     }
00357     
00358     int GetNumLeaks() const { return static_cast<int>(m_Map.size()); }
00359     
00360     void Dump(FILE *hOut) const
00361     {
00362         struct Local_t
00363         {
00364             static const char * DecorSize(int nSize)
00365             {
00366                 static char szOut[32];
00367                                 
00368                 if(nSize >= 1E6)
00369                     ::sprintf(szOut, "%.2f MB", nSize / (float)1E6);
00370                 else if(nSize >= 1E3)
00371                     ::sprintf(szOut, "%.2f KB", nSize / (float)1E3);
00372                 else
00373                     ::sprintf(szOut, "%d B", nSize);
00374                     
00375                 return szOut;
00376             }
00377         };
00378         
00379         bool bEmpty = m_Map.empty();
00380     
00381         ::fprintf(hOut, "\n+------------------------------------------+\n");
00382         ::fprintf(hOut, "| FipS' MEMORY MANAGER (tracking details)  |\n");
00383         ::fprintf(hOut, "| module: %-32s |\n", GetModNm());
00384         ::fprintf(hOut, "+------------------------------+-----------+\n");
00385         ::fprintf(hOut, "|    Max allocated memory size | %-9s |\n",
00386          Local_t::DecorSize(m_nMaxMem));
00387         ::fprintf(hOut, "|              Number of leaks | %-7d %c |\n",
00388          m_Map.size(), bEmpty ? ' ' : '!' );
00389         ::fprintf(hOut, "+------------------------------+--%c--------+",
00390          bEmpty ? '-' : '+');
00391         
00392         if(bEmpty) { ::fprintf(hOut, "\n"); return; }
00393         
00394         ::fprintf(hOut, "---------------------------------"
00395          "+------------+-----------+\n");
00396          
00397         for(Map_t::const_iterator it = m_Map.begin();
00398          it != m_Map.end(); ++it)
00399         {
00400             const CodePos_t &Pos = (*it).second.m_Pos;
00401             ::fprintf(hOut, "| %31s | %-6d | %-31s | 0x%08x | %-9s |\n",
00402              Pos.m_szFile, Pos.m_nLine, Pos.m_szFunc, (size_t)
00403              ((*it).first.m_pAddr), Local_t::DecorSize((*it).second.m_nSize)
00404             );
00405         }
00406         
00407         ::fprintf(hOut, "+---------------------------------+--------+"
00408          "---------------------------------+------------+-----------+\n");
00409     }
00410  
00411  private:
00412  
00413     struct KeyT_t
00414     {
00415         KeyT_t(const void *pAddr) : m_pAddr(pAddr) {}
00416         bool operator < (const KeyT_t &RHS) const
00417          { return m_pAddr < RHS.m_pAddr; }
00418          
00419         const void *m_pAddr;
00420                 
00421      private:
00422      
00423         KeyT_t();
00424     };
00425  
00426     struct ValT_t
00427     {
00428         int m_nSize;
00429         MemOp_e m_MemOp;
00430         CodePos_t m_Pos;
00431         
00432         ValT_t(int nSize, MemOp_e MemOp, CodePos_t Pos):
00433          m_nSize(nSize), m_MemOp(MemOp), m_Pos(Pos) {}
00434          
00435      private:
00436      
00437         ValT_t();
00438     };
00439 
00440 #if defined(FS_MMGR_WORKAROUND1)
00441     typedef const KeyT_t Key_t;
00442     typedef const ValT_t Val_t;
00443 #else
00444     typedef KeyT_t Key_t;
00445     typedef ValT_t Val_t;
00446 #endif
00447 
00448     typedef std::pair<Key_t, Val_t> Pair_t;
00449     typedef std::map<Key_t, Val_t, std::less<Key_t>, Alloc_T<Val_t> > Map_t;
00450      
00451     Map_t m_Map;
00452     
00453     int m_nCurMem;
00454     int m_nMaxMem;
00455     
00456 } g_Tracker;
00457 #endif
00458 //---------------------------------------------------------------------------
00459 #if defined(FS_MMGR_DEF_ATEXIT)
00460 void AtExit()
00461 {
00462     char pszFile[256];
00463     
00464 #if defined(UNDER_CE)
00465 
00466     // there is no concept of the working directory so it is necessary
00467     // to extract one from the module filename
00468      
00469     wchar_t wszTemp[MAX_PATH + 1];
00470     ::GetModuleFileName(0, wszTemp, MAX_PATH);
00471     
00472     size_t i = 0; while(i < MAX_PATH) { char ch = static_cast<wchar_t>
00473      (wszTemp[i]); pszFile[i] = ch; if(ch == '\0') break; ++i; }
00474      
00475     char *pszSep = ::strrchr(pszFile, '\\');
00476     FS_MMGR_ASSERT(pszSep);
00477     *(pszSep + 1) = '\0';
00478     
00479     ::strcat(pszFile, "fs_mmgr_");
00480     ::strcat(pszFile, GetModNm());
00481     ::strcat(pszFile, ".log");
00482     
00483 #else
00484 
00485     ::sprintf(pszFile, "fs_mmgr_%s.log", GetModNm());
00486 
00487 #endif
00488 
00489     FILE *hOutFl = ::fopen(pszFile, "w");
00490             
00491     if(!hOutFl)
00492         return;
00493         
00494     bool bLeaks = false;
00495     
00496 #if defined(FS_MMGR_ENABLE_BASIC_STATS)
00497      g_Stats.Dump(hOutFl);
00498      bLeaks |= g_Stats.GetNumLeaks() > 0 ? true : false;
00499 #endif
00500 
00501 #if defined(FS_MMGR_ENABLE_TRACKING)
00502      g_Tracker.Dump(hOutFl);
00503      bLeaks |= g_Tracker.GetNumLeaks() > 0 ? true : false;
00504 #endif
00505     
00506     ::fclose(hOutFl);
00507     
00508     if(bLeaks)
00509     {
00510         //     RUNTIME ERROR: Memory leaks detected, for more details see
00511         //                    the log file (if the tracking is enabled).
00512         FS_MMGR_ASSERT(0); // ^^^
00513     }
00514 }
00515 #endif
00516 //---------------------------------------------------------------------------
00517 #if defined(FS_MMGR_OWN_OPERATORS)
00518 void * Alloc(size_t uSize)
00519 {
00520 #if defined(FS_MMGR_DEF_ATEXIT)
00521     if(!g_bAtExitSet)
00522     {
00523         ::atexit(AtExit);
00524         g_bAtExitSet = true;
00525     }
00526 #endif
00527 
00528 #if defined(FS_MMGR_ENABLE_BASIC_STATS)
00529     g_Stats.Alloc();
00530 #endif
00531 
00532 #if defined(FS_MMGR_ENABLE_POOL)
00533 #   error Not implemented!
00534     return 0;
00535 #else
00536     return ::malloc(uSize);
00537 #endif
00538 }
00539 #endif
00540 //---------------------------------------------------------------------------
00541 #if defined(FS_MMGR_OWN_OPERATORS)
00542 void Free(void *pAddr)
00543 {
00544 #if defined(FS_MMGR_ENABLE_BASIC_STATS)
00545     g_Stats.Free();
00546 #endif
00547 
00548 #if defined(FS_MMGR_ENABLE_POOL)
00549 #   error Not implemented!
00550 #else
00551     ::free(pAddr);
00552 #endif
00553 }
00554 #endif
00555 //---------------------------------------------------------------------------
00559 const char * GetModNm()
00560 {
00561     if(g_szModNm[0] == '\0')
00562         ::sprintf(g_szModNm, "0x%08x", (size_t)&GetModNm);
00563     
00564     return g_szModNm;
00565 }
00566 //---------------------------------------------------------------------------
00567 } // anonymous namespace
00568 //---------------------------------------------------------------------------
00569 //--- NAMESPACE fs::sys::mem >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00570 //---------------------------------------------------------------------------
00579 void fs::sys::mmgr::SetModNm(const char *pszModNm)
00580 {
00581     if(pszModNm)
00582     {
00583         ::strncpy(g_szModNm, pszModNm, sizeof(g_szModNm));
00584         g_szModNm[sizeof(g_szModNm) - 1] = '\0';
00585     }
00586     else
00587         g_szModNm[0] = '\0';
00588 }
00589 //---------------------------------------------------------------------------
00590 #if defined(FS_MMGR_ENABLE_TRACKING)
00591 void fs::sys::mmgr::aux::Track(const char *pszFunc, const char *pszFile,
00592  int nLine)
00593 {
00594     g_LastPos = CodePos_t(pszFunc, pszFile, nLine);
00595 }
00596 #endif
00597 //---------------------------------------------------------------------------
00598 //--- MEMORY ALLOCATION OPERATORS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00599 //---------------------------------------------------------------------------
00600 #include <fs/sys/fsMemMgr_NoT.h> // turn off the tracking macros
00601 //---------------------------------------------------------------------------
00602 #if defined(FS_MMGR_OWN_OPERATORS)
00603 void * operator new (size_t uSize)
00604 {
00605     void *pAddr = Alloc(uSize);
00606     
00607 #if defined(FS_MMGR_ENABLE_TRACKING)
00608     g_Tracker.Alloc
00609      (pAddr, static_cast<int>(uSize), MOP_NEW, g_LastPos);
00610 #endif
00611     
00612     return pAddr;
00613 }
00614 #endif
00615 //---------------------------------------------------------------------------
00616 #if defined(FS_MMGR_OWN_OPERATORS)
00617 void operator delete (void *pAddr)
00618 {
00619 #if defined(FS_MMGR_ENABLE_TRACKING)
00620     g_Tracker.Free(pAddr, MOP_DELETE);
00621 #endif
00622 
00623     Free(pAddr);
00624 }
00625 #endif
00626 //---------------------------------------------------------------------------
00627 #if defined(FS_MMGR_OWN_OPERATORS)
00628 void * operator new [] (size_t uSize)
00629 {
00630     void *pAddr = Alloc(uSize);
00631     
00632 #if defined(FS_MMGR_ENABLE_TRACKING)
00633     g_Tracker.Alloc
00634      (pAddr, static_cast<int>(uSize), MOP_NEW_ARRAY, g_LastPos);
00635 #endif
00636     
00637     return pAddr;
00638 }
00639 #endif
00640 //---------------------------------------------------------------------------
00641 #if defined(FS_MMGR_OWN_OPERATORS)
00642 void operator delete [] (void *pAddr)
00643 {
00644 #if defined(FS_MMGR_ENABLE_TRACKING)
00645     g_Tracker.Free(pAddr, MOP_DELETE_ARRAY);
00646 #endif
00647 
00648     Free(pAddr);
00649 }
00650 #endif
00651 //---------------------------------------------------------------------------
00652 #include <fs/sys/fsMemMgr.h> // turn on the tracking macros
00653 //---------------------------------------------------------------------------

FipS' Code (Thu Feb 15 22:43:35 2007) - (c) Filip STOKLAS (FipS) - [ www ] [ Guest Book ]