That's actually a fairly interesting question. I compile my own cantera fork within a docker container, and use the equivalent of this approach:
https://rubberduckdebugging.com/, albeit without the duck. Jests aside, I mainly work through the python interface and tightly couple C++ code with corresponding cython wrappers, i.e. I can interactively probe behavior from ipython. I have used valgrind as a big gun if there's hard to track-down memory errors. Python code is easily developed within jupyter (inheritance!). I am aware that there are more sophisticated approaches, but rarely found a need for them. Nevertheless, it would be interesting to hear about other folks' approaches ...
-ingmar-