diff --git a/iface/CMakeLists.txt b/iface/CMakeLists.txt index 17afe0f..33cf7bb 100644 --- a/iface/CMakeLists.txt +++ b/iface/CMakeLists.txt @@ -13,6 +13,7 @@ target_sources(nf7_iface common/container.hh common/exception.hh common/future.hh + common/leak_detector.hh common/observer.hh common/task.hh common/task_context.hh @@ -33,6 +34,7 @@ target_sources(nf7_iface_test common/dealer_test.cc common/container_test.cc common/future_test.cc + common/leak_detector_test.cc common/observer_test.cc common/observer_test.hh common/task_test.cc diff --git a/iface/common/leak_detector.hh b/iface/common/leak_detector.hh new file mode 100644 index 0000000..263a2c1 --- /dev/null +++ b/iface/common/leak_detector.hh @@ -0,0 +1,45 @@ +// No copyright +#pragma once + +#include +#include +#include +#include +#include + +namespace nf7 { +#if !defined(NDEBUG) + + template + class LeakDetector { + public: + LeakDetector() { (void) checker_; ++count_; } + virtual ~LeakDetector() noexcept { --count_; } + + private: + struct Checker { + ~Checker() { + if (count_ > 0) { + std::cerr << "LEAK DETECTED: " << typeid(T).name() << std::endl; + } + } + }; + + public: + static uint64_t count() noexcept { return count_; } + + private: + static inline Checker checker_; + static inline std::atomic count_ = 0; + }; + +#else + + template + class LeakDetector { + public: + static uint64_t count() noexcept { return 0; } + }; + +#endif +} // namespace nf7 diff --git a/iface/common/leak_detector_test.cc b/iface/common/leak_detector_test.cc new file mode 100644 index 0000000..f0348c7 --- /dev/null +++ b/iface/common/leak_detector_test.cc @@ -0,0 +1,21 @@ +// No copyright +#include "iface/common/leak_detector.hh" + +#include + +#include + + +namespace { +class A : private nf7::LeakDetector { }; +} // namespace + +#if !defined(NDEBUG) +TEST(LeakDetector, Counter) { + { + A a; + EXPECT_EQ(nf7::LeakDetector::count(), 1); + } + EXPECT_EQ(nf7::LeakDetector::count(), 0); +} +#endif