I have created template class to easily get the current number of instances a class has. It's threadsafe and I tried to make it as hard as possible to abuse.
#include <atomic>
#include <cstdint>
#include <type_traits>
template<typename t_derived>
struct countable
{
friend t_derived;
struct counter
{
friend countable<t_derived>;
private:
static std::atomic<uint32_t> s_counter;
};
static uint32_t instances()
{
static_assert(std::is_base_of<countable<t_derived>, t_derived>::value,
"Trying to get count of non counted class");
return counter::s_counter;
}
private:
countable()
{
++counter::s_counter;
}
countable(const countable&)
{
++counter::s_counter;
}
~countable()
{
--counter::s_counter;
}
};
template<typename t_derived>
std::atomic<uint32_t> countable<t_derived>::counter::s_counter(0);
Edit:
There seem to be some misunderstandings about this class. I'm sorry, I should've explained it a bit. Here is an example main.cpp. It requires at least C++11:
#include <iostream>
// paste implementation here
struct counted1 : countable<counted1>
{
counted1()
{
std::cout << "counted1::counted1()\n";
}
~counted1()
{
std::cout << "counted1::~counted1()\n";
}
};
struct counted2 : countable<counted2>
{
counted2()
{
std::cout << "counted2::counted2()\n";
}
~counted2()
{
std::cout << "counted2::~counted2()\n";
}
};
int main()
{
std::cout << "counted1 [" << counted1::instances() << "]\n";
std::cout << "counted2 [" << counted2::instances() << "]\n";
counted1 s1;
std::cout << "counted1 [" << counted1::instances() << "]\n";
std::cout << "counted2 [" << counted2::instances() << "]\n";
{
counted1 s2;
counted2 s3;
std::cout << "counted1 [" << counted1::instances() << "]\n";
std::cout << "counted2 [" << counted2::instances() << "]\n";
}
std::cout << "counted1 [" << counted1::instances() << "]\n";
std::cout << "counted2 [" << counted2::instances() << "]\n";
return 0;
}
Why did I make the ctors private & not protected? Simply if they were protected every class could inherit from it. Making them private & declaring the template parameter a friend enforces the correct use of the crtp pattern:
struct my_counted_struct : countable<some_other_struct>{}; // error!
This has the side effect that all actual private data (s_counter) is also exposed to the derived class, so this would be possible:
struct my_struct : countable<my_struct>
{
void do_something_nasty()
{
countable<my_struct>::s_counter = 0;
}
};
That's why the actual private data is in the inner class counter which declares countable a friend, giving it access to its private data.
mainso we can compile it and see it working. Thanks! \$\endgroup\$