diff --git a/src/Makefile.am b/src/Makefile.am index 24c716daf..b04fb4d9c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -452,6 +452,8 @@ supertuxkart_SOURCES = \ utils/aligned_array.hpp \ utils/constants.hpp \ utils/constants.cpp \ + utils/leak_check.cpp \ + utils/leak_check.hpp \ utils/no_copy.hpp \ utils/profiler.cpp \ utils/profiler.hpp \ diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 68ae5dbb3..bc1955a9f 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -645,10 +645,9 @@ namespace GUIEngine int title_font_height; } using namespace Private; - + PtrVector needsUpdate; - //FIXME: the contents of this vector are never ever freed PtrVector g_loaded_screens; float dt = 0; @@ -760,6 +759,8 @@ namespace GUIEngine if (g_current_screen != NULL) g_current_screen->elementsWereDeleted(); g_current_screen = NULL; + needsUpdate.clearWithoutDeleting(); + gui_messages.clear(); } // clear @@ -769,10 +770,6 @@ namespace GUIEngine { clear(); - //FIXME: I'm not very sure why this isn't called in the regular - // clear() method?? - needsUpdate.clearWithoutDeleting(); - gui_messages.clear(); } // cleanForGame @@ -787,7 +784,7 @@ namespace GUIEngine // ------------------------------------------------------------------------ void switchToScreen(const char* screen_name) - { + { needsUpdate.clearWithoutDeleting(); // clean what was left by the previous screen @@ -835,6 +832,11 @@ namespace GUIEngine } // reshowCurrentScreen // ------------------------------------------------------------------------ + + /** + * Clean some of the cached data, either for a shutdown or a reload. + * If this is a shutdown then you also need to call free(). + */ void cleanUp() { // There is no need to delete the skin, the gui environment holds it @@ -865,6 +867,19 @@ namespace GUIEngine // kill everything along the device } // cleanUp + // ------------------------------------------------------------------------ + + /** + * To be called after cleanup(). + * The difference between cleanup() and free() is that cleanUp() just removes + * some cached data but does not actually uninitialize the gui engine. This + * does. + */ + void free() + { + g_loaded_screens.clearAndDeleteAll(); + } + // ------------------------------------------------------------------------ void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager* state_manager ) diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index 243b88f96..8ae4b06d7 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -100,11 +100,10 @@ namespace GUIEngine */ void init(irr::IrrlichtDevice* device, irr::video::IVideoDriver* driver, AbstractStateManager* state_manager); - /** - * \brief frees all resources allocated by GUIEngine::init and subsequent uses of the GUI engine. - */ void cleanUp(); + void free(); + /** * \return the irrlicht device object diff --git a/src/guiengine/modaldialog.hpp b/src/guiengine/modaldialog.hpp index c91507ca3..ef0e21462 100644 --- a/src/guiengine/modaldialog.hpp +++ b/src/guiengine/modaldialog.hpp @@ -26,6 +26,7 @@ //#include "guiengine/layout_manager.hpp" #include "guiengine/skin.hpp" #include "input/input_manager.hpp" +#include "utils/leak_check.hpp" //class PlayerProfile; @@ -75,7 +76,9 @@ namespace GUIEngine */ virtual void loadedFromFile() {} - public: + public: + LEAK_CHECK() + virtual ~ModalDialog(); /** Returns whether to block event propagation (usually, you will want to block events you processed) */ diff --git a/src/guiengine/screen.hpp b/src/guiengine/screen.hpp index c7c3511d0..bbbe5ae96 100644 --- a/src/guiengine/screen.hpp +++ b/src/guiengine/screen.hpp @@ -39,6 +39,8 @@ using namespace irr; #include "input/input.hpp" #include "utils/ptr_vector.hpp" +#include "utils/leak_check.hpp" + /** * \ingroup guiengine */ @@ -113,6 +115,8 @@ namespace GUIEngine public: + LEAK_CHECK() + /** * \ingroup guiengine * \brief Loads a GUI screen from its XML file. diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index 7a8309111..8fde962ac 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -31,6 +31,8 @@ namespace irr namespace video { class ITexture; } namespace gui { class IGUIElement; class IGUIFont; class IGUISpriteBank; } } + +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" /** @@ -260,6 +262,8 @@ namespace GUIEngine #ifdef USE_PER_LINE_BACKGROUND public: #endif + LEAK_CHECK() + void drawBoxFromStretchableTexture(SkinWidgetContainer* w, const irr::core::rect< irr::s32 > &dest, BoxRenderParams& params, bool deactivated=false, const irr::core::rect* clipRect=NULL); diff --git a/src/guiengine/widget.hpp b/src/guiengine/widget.hpp index 85b715b3e..48ce71121 100644 --- a/src/guiengine/widget.hpp +++ b/src/guiengine/widget.hpp @@ -30,7 +30,6 @@ namespace irr #include "guiengine/skin.hpp" #include "utils/constants.hpp" #include "utils/ptr_vector.hpp" -//#include "utils/vec3.hpp" namespace GUIEngine { @@ -247,7 +246,7 @@ namespace GUIEngine irr::core::stringw m_tooltip_text; public: - + /** * This is set to NULL by default; set to something else in a widget to mean * that events happening on this widget should also be passed to m_event_handler->transmitEvent, diff --git a/src/guiengine/widgets/CGUIEditBox.h b/src/guiengine/widgets/CGUIEditBox.h index 147528e59..a95cf3408 100644 --- a/src/guiengine/widgets/CGUIEditBox.h +++ b/src/guiengine/widgets/CGUIEditBox.h @@ -9,6 +9,7 @@ #include "IGUIEditBox.h" #include "irrArray.h" #include "IOSOperator.h" +#include "utils/leak_check.hpp" #include "utils/time.hpp" @@ -19,6 +20,8 @@ using namespace gui; { public: + LEAK_CHECK() + //! constructor CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect& rectangle, bool is_rtl); diff --git a/src/guiengine/widgets/bubble_widget.hpp b/src/guiengine/widgets/bubble_widget.hpp index 884943e54..481982977 100644 --- a/src/guiengine/widgets/bubble_widget.hpp +++ b/src/guiengine/widgets/bubble_widget.hpp @@ -22,6 +22,7 @@ #include #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" namespace GUIEngine { @@ -49,6 +50,8 @@ namespace GUIEngine public: + LEAK_CHECK() + BubbleWidget(); virtual void add(); diff --git a/src/guiengine/widgets/button_widget.hpp b/src/guiengine/widgets/button_widget.hpp index 5eaaef205..89c058f53 100644 --- a/src/guiengine/widgets/button_widget.hpp +++ b/src/guiengine/widgets/button_widget.hpp @@ -27,6 +27,7 @@ #include #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -38,6 +39,9 @@ namespace GUIEngine class ButtonWidget : public Widget { public: + + LEAK_CHECK() + ButtonWidget(); virtual ~ButtonWidget() {} diff --git a/src/guiengine/widgets/check_box_widget.hpp b/src/guiengine/widgets/check_box_widget.hpp index 8eedce87c..2b3d70576 100644 --- a/src/guiengine/widgets/check_box_widget.hpp +++ b/src/guiengine/widgets/check_box_widget.hpp @@ -21,6 +21,7 @@ #define HEADER_CHECKBOX_HPP #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -35,6 +36,9 @@ namespace GUIEngine EventPropagation transmitEvent(Widget* w, std::string& originator, const int playerID); public: + + LEAK_CHECK() + CheckBoxWidget(); virtual ~CheckBoxWidget() {} diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.hpp b/src/guiengine/widgets/dynamic_ribbon_widget.hpp index 995a9ddaf..5a217b86e 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.hpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.hpp @@ -24,6 +24,7 @@ #include "guiengine/widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -172,6 +173,7 @@ namespace GUIEngine public: + LEAK_CHECK() /** * \param combo Whether this is a "combo" ribbon, i.e. whether there is always one selected item. diff --git a/src/guiengine/widgets/icon_button_widget.hpp b/src/guiengine/widgets/icon_button_widget.hpp index 4b6854520..3b524eead 100644 --- a/src/guiengine/widgets/icon_button_widget.hpp +++ b/src/guiengine/widgets/icon_button_widget.hpp @@ -28,6 +28,7 @@ namespace irr } #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -71,6 +72,8 @@ namespace GUIEngine public: + LEAK_CHECK() + /** Whether to make the widget included in keyboard navigation order when adding */ bool m_tab_stop; diff --git a/src/guiengine/widgets/label_widget.hpp b/src/guiengine/widgets/label_widget.hpp index d049979dd..634bdb00c 100644 --- a/src/guiengine/widgets/label_widget.hpp +++ b/src/guiengine/widgets/label_widget.hpp @@ -24,6 +24,7 @@ #include #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -41,14 +42,17 @@ namespace GUIEngine /** Current scroll offset. */ float m_scroll_offset; + public: + LEAK_CHECK() + /** Constructs the label widget. Parameter: * \param title True if the special title font should be used. * \param bright True if a bright color should be used * \note \c title and \c bright are mutually exclusive */ - LabelWidget(bool title=false, bool bright=false); + LabelWidget(bool title=false, bool bright=false); virtual ~LabelWidget() {} diff --git a/src/guiengine/widgets/list_widget.hpp b/src/guiengine/widgets/list_widget.hpp index 30af9a228..3fc52c376 100644 --- a/src/guiengine/widgets/list_widget.hpp +++ b/src/guiengine/widgets/list_widget.hpp @@ -24,6 +24,7 @@ #include "guiengine/widget.hpp" #include "guiengine/widgets/button_widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace irr { namespace gui { class STKModifiedSpriteBank; } } @@ -84,6 +85,9 @@ namespace GUIEngine IListWidgetHeaderListener* m_listener; public: + + LEAK_CHECK() + ListWidget(); SkinWidgetContainer m_selection_skin_info; diff --git a/src/guiengine/widgets/model_view_widget.hpp b/src/guiengine/widgets/model_view_widget.hpp index ad7d8c825..96fc9b4e5 100644 --- a/src/guiengine/widgets/model_view_widget.hpp +++ b/src/guiengine/widgets/model_view_widget.hpp @@ -25,6 +25,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/widgets/icon_button_widget.hpp" #include "utils/aligned_array.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -59,6 +60,8 @@ namespace GUIEngine public: + LEAK_CHECK() + ModelViewWidget(); ~ModelViewWidget(); diff --git a/src/guiengine/widgets/progress_bar_widget.hpp b/src/guiengine/widgets/progress_bar_widget.hpp index 91b1db039..137b2aa9e 100644 --- a/src/guiengine/widgets/progress_bar_widget.hpp +++ b/src/guiengine/widgets/progress_bar_widget.hpp @@ -27,6 +27,7 @@ #include #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -50,6 +51,9 @@ namespace GUIEngine int m_value; public: + + LEAK_CHECK() + ProgressBarWidget(); virtual ~ProgressBarWidget() {} diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index 12062e7f7..01796b222 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -24,6 +24,7 @@ #include "guiengine/widget.hpp" #include "guiengine/widgets/icon_button_widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" #include @@ -82,8 +83,11 @@ namespace GUIEngine IRibbonListener* m_listener; + public: + LEAK_CHECK() + /** * Internal identifier of filler items that are added in a ribbon widget to fill * lines when the number of items cannot be divided by the number of rows in the grid diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 503035a32..7b44754e2 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -27,6 +27,7 @@ namespace irr } #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -90,6 +91,8 @@ namespace GUIEngine public: + LEAK_CHECK() + SpinnerWidget(const bool gauge=false); virtual ~SpinnerWidget() {} virtual void move(const int x, const int y, const int w, const int h); diff --git a/src/guiengine/widgets/text_box_widget.hpp b/src/guiengine/widgets/text_box_widget.hpp index 28fc76d37..766f0742b 100644 --- a/src/guiengine/widgets/text_box_widget.hpp +++ b/src/guiengine/widgets/text_box_widget.hpp @@ -23,6 +23,7 @@ #include #include "guiengine/widget.hpp" +#include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" namespace GUIEngine @@ -48,6 +49,9 @@ namespace GUIEngine virtual int getHeightNeededAroundLabel() const { return 10; } public: + + LEAK_CHECK() + TextBoxWidget(); ~TextBoxWidget() { diff --git a/src/ide/Xcode/STK_XCode.xcodeproj/project.pbxproj b/src/ide/Xcode/STK_XCode.xcodeproj/project.pbxproj index 372272647..cee2ea4f5 100644 --- a/src/ide/Xcode/STK_XCode.xcodeproj/project.pbxproj +++ b/src/ide/Xcode/STK_XCode.xcodeproj/project.pbxproj @@ -341,6 +341,7 @@ 95AAD98012BAD36300B7B8A3 /* tutorial_screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AAD97E12BAD36300B7B8A3 /* tutorial_screen.cpp */; }; 95B5CD14102DE08F00EF2001 /* device_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95B5CD13102DE08F00EF2001 /* device_config.cpp */; }; 95BF1E68127513A100F78AE7 /* max_speed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95BF1E66127513A100F78AE7 /* max_speed.cpp */; }; + 95C631A4142AC79500416D47 /* leak_check.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95C631A3142AC79500416D47 /* leak_check.cpp */; }; 95C77D631069589B0080838E /* ambient_light_sphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95C77D621069589B0080838E /* ambient_light_sphere.cpp */; }; 95C77D66106958A50080838E /* check_line.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95C77D65106958A50080838E /* check_line.cpp */; }; 95C77D6F106958E10080838E /* check_sphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95C77D6D106958E10080838E /* check_sphere.cpp */; }; @@ -1277,6 +1278,8 @@ 95C2B1E70F296546000D3E5D /* string_utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = string_utils.hpp; path = ../../utils/string_utils.hpp; sourceTree = SOURCE_ROOT; }; 95C2B1E80F296546000D3E5D /* vec3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = vec3.cpp; path = ../../utils/vec3.cpp; sourceTree = SOURCE_ROOT; }; 95C2B1E90F296546000D3E5D /* vec3.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = vec3.hpp; path = ../../utils/vec3.hpp; sourceTree = SOURCE_ROOT; }; + 95C631A3142AC79500416D47 /* leak_check.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = leak_check.cpp; path = ../../utils/leak_check.cpp; sourceTree = SOURCE_ROOT; }; + 95C631B3142AC95500416D47 /* leak_check.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = leak_check.hpp; path = ../../utils/leak_check.hpp; sourceTree = SOURCE_ROOT; }; 95C65D760F532F7D00BE7BA7 /* xml_node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = xml_node.cpp; path = ../../io/xml_node.cpp; sourceTree = SOURCE_ROOT; }; 95C65D770F532F7D00BE7BA7 /* xml_node.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = xml_node.hpp; path = ../../io/xml_node.hpp; sourceTree = SOURCE_ROOT; }; 95C77D611069589B0080838E /* ambient_light_sphere.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ambient_light_sphere.hpp; path = ../../tracks/ambient_light_sphere.hpp; sourceTree = SOURCE_ROOT; }; @@ -2648,6 +2651,8 @@ children = ( 9553823910FD4FEC00737979 /* constants.cpp */, 95C2B1E00F296546000D3E5D /* constants.hpp */, + 95C631A3142AC79500416D47 /* leak_check.cpp */, + 95C631B3142AC95500416D47 /* leak_check.hpp */, 9540E2570FD5F8FD002985B8 /* no_copy.hpp */, 957899B613C8E05F007AA5A3 /* profiler.cpp */, 957899B713C8E05F007AA5A3 /* profiler.hpp */, @@ -3158,6 +3163,7 @@ 958806E913EB675F005F90FE /* track_sector.cpp in Sources */, 957A2D291405E21D00F45B22 /* hit_sfx.cpp in Sources */, 957817DC142142C500AD07B2 /* referee.cpp in Sources */, + 95C631A4142AC79500416D47 /* leak_check.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3238,6 +3244,7 @@ PREBINDING = NO; PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; PRODUCT_NAME = SuperTuxKart; + SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; }; name = Debug; }; diff --git a/src/main.cpp b/src/main.cpp index 13027664d..a4a9506ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,7 @@ #include "tracks/track_manager.hpp" #include "tutorial/tutorial_manager.hpp" #include "utils/constants.hpp" +#include "utils/leak_check.hpp" #include "utils/translation.hpp" // ============================================================================ @@ -1142,6 +1143,10 @@ int main(int argc, char *argv[] ) cleanSuperTuxKart(); +#ifdef DEBUG + MemoryLeaks::checkForLeaks(); +#endif + return 0 ; } diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index d5a48c996..123b7b82e 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -78,6 +78,8 @@ class FocusDispatcher : public Widget public: + LEAK_CHECK() + FocusDispatcher(KartSelectionScreen* parent) : Widget(WTYPE_BUTTON) { m_parent = parent; @@ -147,6 +149,7 @@ public: m_red_mark_widget = NULL; m_parent = parent; } + void setID(const int m_playerID) { PlayerNameSpinner::m_playerID = m_playerID; @@ -223,6 +226,9 @@ class PlayerKartWidget : public Widget, public SpinnerWidget::ISpinnerConfirmLis #endif public: + + LEAK_CHECK() + /** Sub-widgets created by this widget */ //LabelWidget* m_player_ID_label; PlayerNameSpinner* m_player_ident_spinner; @@ -369,7 +375,7 @@ public: // ------------------------------------------------------------------------- ~PlayerKartWidget() - { + { if (GUIEngine::getFocusForPlayer(m_playerID) == this) { GUIEngine::focusNothingForPlayer(m_playerID); @@ -532,6 +538,7 @@ public: m_player_ident_spinner->setListener(NULL); m_player_ident_spinner->getIrrlichtElement()->remove(); m_player_ident_spinner->elementRemoved(); + delete m_player_ident_spinner; m_player_ident_spinner = NULL; sfx_manager->quickSound( "wee" ); diff --git a/src/states_screens/state_manager.cpp b/src/states_screens/state_manager.cpp index c67629639..6eece3624 100644 --- a/src/states_screens/state_manager.cpp +++ b/src/states_screens/state_manager.cpp @@ -218,6 +218,7 @@ void StateManager::onTopMostScreenChanged() void StateManager::onStackEmptied() { GUIEngine::cleanUp(); + GUIEngine::free(); main_loop->abort(); } // onStackEmptied diff --git a/src/utils/leak_check.cpp b/src/utils/leak_check.cpp new file mode 100644 index 000000000..7339bf030 --- /dev/null +++ b/src/utils/leak_check.cpp @@ -0,0 +1,117 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#ifdef DEBUG + +/** Switch this to 1 to get the backtrace of the leaks (slows down execution a little) + Atm only implemented for OSX */ +#define GET_STACK_TRACE 0 + +#if (GET_STACK_TRACE == 1) && defined(MAC_OS_X_VERSION_10_5) +#include +#include +#endif + +#include + +#include "utils/leak_check.hpp" +#include + +namespace MemoryLeaks +{ + + std::set g_all_objs; + + void addObj(MyObject* obj) + { + g_all_objs.insert(obj); + } + + void removeObj(MyObject* obj) + { + g_all_objs.erase(obj); + delete obj; + } + + MyObject::MyObject(AbstractLeakCheck* objArg) + { + obj = objArg; + +#if (GET_STACK_TRACE == 1) && defined(MAC_OS_X_VERSION_10_5) + + const int maxsize = 32; + void* callstack[maxsize]; + stackSize = backtrace(callstack, maxsize); + + stack = backtrace_symbols(callstack, stackSize); +#else + stack = NULL; +#endif + + } + + void MyObject::print() + { + obj->print(); + + if (stack == NULL) + { + printf(" (No stack information available)\n"); + } + else + { + for (int i = 0; i < stackSize; ++i) + { + printf(" %s\n", stack[i]); + } + } + + } + + void checkForLeaks() + { + + std::cout << "checking for leaks... " << std::endl; + + if (g_all_objs.size()>0) + { + std::cout << "leaks detected!!" << std::endl; + std::cout << "\n\n* * * * WARNING * * * * WARNING * * * * MEMORY LEAK! * * * *\n" << std::endl; + } + else + { + std::cout << "ok (no watched class left leaking)" << std::endl; + return; + } + std::cout << "LEAK CHECK: " << g_all_objs.size() << " watched objects leaking" << std::endl; + + std::set::iterator it; + for (it = g_all_objs.begin(); it != g_all_objs.end(); ++it) + { + (*it)->print(); + } + /* + for (int n=0; n