Overloading New and Delete to track memory in shared_ptr.
Hi again, Well I'm making pretty good progress in learning proper way to use shared_ptr's but I'm still a little nervous about leaking memory, especially if I manage to do something I'm not supposed to do and don't recognize that a memory leak may be occuring. I've used the overloading new/delete before to help track memory leaks and I was wondering if that would be possible with shared_ptrs. I tried my old header files with and saw tons of leaks but I think its because my New that I use logs the creation to a Tracer class but since the Delete happens in the shared_ptr, its not using the overloaded Delete that removes stuff from the tracer when its deleted. I've looked around and found some examples of making a custom deleter to pass into the shared ptr when creating a new shared_ptr which should work but I have some worries about it. I'm not quite sure what the recommended way of doing this would be. About the only thing I can think of would be to have two different deleters which would be conditionally compiled something like this : //Overloaded New to log allocation to a tracer, theres a define to add the file and line number to the new call #ifndef NDEBUG void * operator new (unsigned int size, char const * file, int line) { void * p = new (size); if (Tracer::Ready) NewTrace.Add (p, file, line); return p; } struct deleter { void operator() (void * p) const { if (Tracer::Ready) NewTrace.Remove(p); delete p; } } #else struct deleter { void operator() (void * p) const { delete p; } } #endif //NewTrace is an extern'd object in the Main.cpp file So then I'd pass in the deleter to the shared_ptr and then whichever deleter was defined would be passed into the shared_ptr. I'm kinda cobbling together a few different things I've seen but I think that with this I could include the header file in the .cpp file of any class that I want to track the memory of and then just make sure I send in the deleter when I reset or make a new shared ptr. For instance in my LoggerFactory.cpp file : #include "../include/Logger.hpp" #include "../include/LoggerFactory.hpp" #include "../include/dbnew.hpp" LoggerMap LoggerFactory::loggers; boost::shared_ptr<Logger> LoggerFactory::getInstance(std::string& logger) { boost::shared_ptr<Logger>& TheLoggerRef = loggers[logger]; if(!TheLoggerRef.get()) TheLoggerRef.reset(new Logger(logger),deleter()); return TheLoggerRef; } So then the dbnew would define the deleter to use for the Logger object, if it was a debug build it would also create the overloaded new operator, define the _FILE_ and _LINE_ macros to send into the new New operator. And if its not the debug build then essentially the normal deleter is given to the shared_ptr and everything procedes as normal. Is this a good way to go about adding memory leak checking? I've looked for a new memory leak checkers like valgrind but thats only available on Linux and I'm stuck on windows.. and all the memory checkers I've been able to find only support VC++ or borland and I use gcc. So I would like a nice simple way that I can drop right in, which is what I'm going for with the overloading new and the custom deleter. Joshua.
Joshua Little wrote:
Hi again, Well I'm making pretty good progress in learning proper way to use shared_ptr's but I'm still a little nervous about leaking memory, especially if I manage to do something I'm not supposed to do and don't recognize that a memory leak may be occuring. I've used the overloading new/delete before to help track memory leaks and I was wondering if that would be possible with shared_ptrs. I tried my old header files with and saw tons of leaks but I think its because my New that I use logs the creation to a Tracer class but since the Delete happens in the shared_ptr, its not using the overloaded Delete that removes stuff from the tracer when its deleted.
Looking at the code you posted, it seems that you are using the Tracer from http://www.relisoft.com/book/tech/9new.html Given that, I don't see why the operator delete overload from the page: void operator delete (void * p) { if (Tracer::Ready) NewTrace.Remove (p); free (p); } isn't called by shared_ptr. [...]
struct deleter { void operator() (void * p) const { delete p; } }
Deleting the pointer as void* is a very bad idea, and your compiler should warn you about it. No destructor will be called, at best. I think that the above operator delete overload should be sufficient and there should be no need to use custom deleters. You might also be interested in the two (underdocumented) source files in libs/smart_ptr/src. sp_debug_hooks.cpp checks for illegal memory/shared_ptr operations (but has no leak detection). sp_collector.cpp allows you to detect unreachable cyclic shared_ptr references (which is pretty much the only way to leak memory with shared_ptr) by calling std::size_t find_unreachable_objects(bool report); You need to #define BOOST_SP_ENABLE_DEBUG_HOOKS for either of these to work.
participants (2)
-
Joshua Little
-
Peter Dimov