I've investigated this for an industrial-strength, large-scale project in the past. It's technologically interesting; to collect, it "stops the world" (freezing all threads but one using, e.g., POSIX signals) and then uses the CPU registers, each thread's stack, and global variables as "roots" to be traversed to find live objects. In a way, this is even more general than just C or C++; it really works for any static language, including assembly. One caveat is that if your code represents pointers in non-obvious ways, the objects referred to will look like garbage to this collector. I'm afraid it's not as unusual as one might hope for low-level code to represent pointers in funny ways...
I used this and had a good experience with it. The project I used it on was ~150K lines of C and had lots of developers from different organizations contributing code. That made it a pretty good example of a project that was having trouble growing because of manual memory management. On such a project, just defining and documenting who should call free() for a given data structure is hard and actually enforcing those rules (and figuring out what component broke them) is much harder.
We were able to pretty easily integrate it into the project (we already had macros indirecting all calls to malloc() and free()) and initially use it as a leak detector. After that we were able to trust it to handle deallocation where it made sense.
A neat feature of this collector is that you can tell it during allocation that a block is guaranteed to have no pointers in it for those cases where you can know that (blacklisting big chunks of floating point data or images). This improves the performance and accuracy of the conservative collection as it doesn't need to scan those blocks. That makes it less objectionable if you are accustomed to the level of control you get with C.
If I were to build a big system in C again, I would use it from the beginning. But I am unlikely to build such a big system in C these days.
Ever single (good) programmer I know is aware of Hans-Boehm GC, but doesn't use it for any projects. In fact I am yet to see a project that uses it and I've seen quite a lot of them to date.
personally, i am of the opinion that RAII-style object lifetime management as implemented in C++ is already far superior to garbage collection. but maybe somebody can convince me otherwise.
You can't do precise GC in C++ because you can't find all valid pointers.
Two of the "can't handle" cases are:
(1) the XOR trick to represent the prev/next pointer for a doubly-linked list with a single field.
(2) Ullman's set set representation which uses an array of values which may, or may not, be valid pointers. You don't know without consulting another structure. (The whole point of this representation is that you don't clear things on initialization.)