This is a classic problem in garbage collector design. Take a look at the Garbage Collection article on Wikipedia, it's really good in presenting the different trade-offs in garbage collector design. The "more evolved" algorithms like tri-color marking are actually quite simple and easy to implement. I've used that those instructions to implement a tracing collector for my own Lisp implementation in C.
The most complex thing to handle in tracing garbage collectors is walking object trees (e.g. finding references to "live" objects). If you are writing an interpreter for another language, this is not too hard because you can wire in facilities for this in your root object class (or other common denominator to all objects). However, if you're writing a garbage collector for C++ in C++, then you'll have a hard time doing this because you need to inspect object contents to find pointers to other allocated regions of memory.
If you are writing a garbage collector for educational purposes, I recommend that you look into writing an interpreter for another language (one that does not have direct access to pointers). If you're writing a collector for C++ in C++ with the intent of using it in production software, I strongly recommend that you use an existing production-quality implementation instead.