#include <cassert>
#include <cstddef>
#include <atomic>
#undef dVIEWNUMBERS
#ifdef dVIEWNUMBERS
#ifndef _IOSTREAM_
#error include <iostream> first
#endif
#undef dVIEWNUMBERS
#define dVIEWNUMBERS \
std::cout << "instances = " << Instances() << std::endl;
#else
#define dVIEWNUMBERS
#endif
namespace tools{
// счетчик созданных экземпляров класса
template<class T> class Copies
{
typedef std::atomic<size_t>
count_t;
public:
~Copies()
{
// количество вызванных деструкторов больше,
// чем количество предшествующих им конструкторов
// (возможная причина такой неисправности -
// запуск диструктора ресурса в многопоточной среде)
assert( NumInstances() > 0 &&
"ERROR: DESTRUCTOR CALLED WITHOUT CONSTRUCTOR" );
--NumInstances();
dVIEWNUMBERS;
}
Copies() { ++NumInstances(); dVIEWNUMBERS; }
Copies(const Copies&) { ++NumInstances(); dVIEWNUMBERS; }
Copies(Copies&&) { ++NumInstances(); dVIEWNUMBERS; }
static size_t Instances() { return NumInstances(); }
private:
static count_t& NumInstances()
{ static count_t n(0); return n; }
};
}// namespace tools
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
#include <iostream>
using namespace std;
template <class T>
class Pointer
{
T *p;
int counter;
Pointer *k;
public:
Pointer(T *_p) : p(_p),counter(1),k(NULL)
{}
~Pointer()
{
if (k) (k->counter)--;
counter--;
if(!counter && !k) delete p;
}
Pointer(Pointer &rhs)
{
rhs.counter++;
counter = 1;
k = &rhs;
p = rhs.p;
}
T* operator->() { return p; }
int users()const { return counter; }
};
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
struct ICat
{
// <--- отсутствует виртуальный диструктор
// однако несмотря на это
// смарт-поинтер должен суметь
// позвать диструктор наследника
// --- виртуальную функцию задействуем
// что бы проверить ресурс смарт-поинтера на
// консистентность
// в случае невалидного указателя на vtbl
// скорее всего получим краш времени выполнения
virtual void foo()const=0;
};
class Cat : public ICat, public tools::Copies<ICat>
{
public:
Cat() { cout << "ctor Cat " << this << endl; }
Cat(const Cat&) { cout << "copy Cat " << this << endl; }
Cat(Cat&&) { cout << "move Cat " << this << endl; }
~Cat() {cout << "dtor Cat " << this << endl; }
virtual void foo()const { std::cout <<"cat\n"; }
};
int main()
{
std::cout << "hello, world\n";
{
// --- тест на конкретный тип ресурса
Pointer<Cat> p1(new Cat);
Pointer<Cat> p2 = p1;
assert(Cat::Instances()==1 && "LOGIC ERROR");
p1->foo();
p2->foo();
Pointer<Cat> p3(new Cat);
Pointer<Cat> p4 = p3;
assert(Cat::Instances()==2 && "LOGIC ERROR");
p3->foo();
p4->foo();
}
assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
{
// --- тест работы с интерфейсом
Pointer<ICat> p1(new Cat);
Pointer<ICat> p2 = p1;
assert(Cat::Instances()==1 && "LOGIC ERROR");
p1->foo();
p2->foo();
Pointer<Cat> p3(new Cat);
Pointer<Cat> p4 = p3;
assert(Cat::Instances()==2 && "LOGIC ERROR");
p3->foo();
p4->foo();
}
assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
}