Счетчик объектов
От: matrixman  
Дата: 21.01.03 10:48
Оценка:
Предполагается, что каждый объект в программе при создании получает имя: ИМЯКЛАССА_N, где N номер объекта. В классе написал счетчик

class A
{
LPSTR m_lpName;
static UINT m_uCounter;
...
}


и в начале инициализирую счетчик нулем.
В конструкторе увеличиваю счетчик на единицу и создаю имя название объекта в m_lpName. Это все работает хорошо.
Проблемы начинаются, если происходит наследование

class В: public A


ведь статическую переменную нельзя проинициировать нулем снова. Поэтому нумерация экземпляров класа В продолжается с номера последнего объекта типа А. Что делать?
Re: Счетчик объектов
От: ssm Россия  
Дата: 21.01.03 10:59
Оценка:
Здравствуйте, matrixman, Вы писали:

M>ведь статическую переменную нельзя проинициировать нулем снова. Поэтому нумерация экземпляров класа В продолжается с номера последнего объекта типа А. Что делать?


template<class T>
class Counter{
    static int count;    
protected:
    Counter(){count++;};
    Counter(const Counter & obj){count++;};
    ~Counter(){count--;};
public:
    static int Count(){return count;}    
};
template<class T>
int Counter<T>::count = 0;


вот для твоих классов:
class A : public Counter<A>
class B : public A, public Counter<B>


значения получаешь так:

std::cout << Counter<A>::Count();
std::cout << Counter<B>::Count();
Re: Счетчик объектов
От: Anton V. Kolotaev  
Дата: 21.01.03 11:02
Оценка: 2 (1)
Здравствуйте, matrixman, Вы писали:

M>ведь статическую переменную нельзя проинициировать нулем снова. Поэтому нумерация экземпляров класа В продолжается с номера последнего объекта типа А. Что делать?




template <class T>
   struct instances
{
   unsigned value;
}

class A 
{
    const int _instance;
public:
    A() : _instance (++instances<A>::value) 
    {
     /// ....
    }

    ~A() { --instances<A>::value;  }
};

class B : public A 
{
    const int _instance;
public:
    B() : _instance (++instances<B>::value) 
    {
     /// ....
    }
    ~B() { --instances<B>::value;  }
};

// в .cpp
instances<A>::value = 0;
instances<B>::value = 0;
Re[2]: Счетчик объектов
От: ssm Россия  
Дата: 21.01.03 11:06
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>class A : private Counter<A>
ssm>class B : public A, private Counter<B>
Re[2]: Счетчик объектов
От: matrixman  
Дата: 21.01.03 11:12
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>вот для твоих классов:

ssm>
ssm>class A : public Counter<A>
ssm>class B : public A, public Counter<B>
ssm>


Большое спасибо Еще один вопрос. Но вот тогда получается что класс В будет содержать методы и класса Counter<A>?
Re[3]: Счетчик объектов
От: ssm Россия  
Дата: 21.01.03 11:15
Оценка: 3 (1)
Здравствуйте, matrixman, Вы писали:


M>Еще один вопрос. Но вот тогда получается что класс В будет содержать методы и класса Counter<A>?


сделай закрытое наследование
Re[4]: Счетчик объектов
От: matrixman  
Дата: 21.01.03 11:21
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Здравствуйте, matrixman, Вы писали:


ssm>

M>>Еще один вопрос. Но вот тогда получается что класс В будет содержать методы и класса Counter<A>?

ssm>сделай закрытое наследование


OK
Re: Счетчик объектов
От: Владик Россия  
Дата: 21.01.03 11:27
Оценка:
Здравствуйте, matrixman, Вы писали:

M>Предполагается, что каждый объект в программе при создании получает имя: ИМЯКЛАССА_N, где N номер объекта. В классе написал счетчик


Если нужно считать ориентируясь только лишь на названия классов, то имеет смысл "набор счетчиков" вынести отдельно, получая доступ к соответсвующему счетчику по имени класса.
Как все запущенно...
Re[2]: Счетчик объектов
От: matrixman  
Дата: 21.01.03 11:29
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:


AV>
AV>    A() : _instance (++instances<A>::value)

Не совсем понятно что это значит
Re[3]: Счетчик объектов
От: Anton V. Kolotaev  
Дата: 21.01.03 11:32
Оценка:
Здравствуйте, matrixman, Вы писали:

M>Здравствуйте, Anton V. Kolotaev, Вы писали:


M>

AV>>
AV>>    A() : _instance (++instances<A>::value) 
M>

M>Не совсем понятно что это значит

инкрементируется член-данных value класса instances<A>.

Что именно неясно??
Re[4]: Счетчик объектов
От: matrixman  
Дата: 21.01.03 11:38
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AV>Здравствуйте, matrixman, Вы писали:


M>>Здравствуйте, Anton V. Kolotaev, Вы писали:


M>>

AV>>>
AV>>>    A() : _instance (++instances<A>::value) 
M>>

M>>Не совсем понятно что это значит

AV>инкрементируется член-данных value класса instances<A>.


AV>Что именно неясно??

Все, Дошло!!!
Re: Счетчик объектов
От: Кодт Россия  
Дата: 21.01.03 12:04
Оценка:
Здравствуйте, matrixman, Вы писали:

M>Предполагается, что каждый объект в программе при создании получает имя: ИМЯКЛАССА_N, где N номер объекта.


<>
Народ уже откликнулся, пока я писал... Тем не менее.

Варианты решения:

1) RTTI для определения имени класса данного объекта; глобальная динамическая таблица имя_класса -> число

typedef unsigned long serial_t;

class CSerialNumberTable
{
private:
  typedef std::map< std::string, serial_t > table_t;
  table_t table_;

public:
  serial_t next(const char* s)        { return ++(table_[s]); }
  serial_t next(std::string const& s) { return ++(table_[s]); }

  serial_t next(type_info const& t)   { return next(t.name()); }

  template< class T >
  serial_t next_obj(T const& t) { return next(typeid(t)); }

  template< class T >
  serial_t next_ptr(T const* p) { return next(*t); }

  template< class T >
  serial_t next_type(T* = 0) { return next(typeid(T const))); }
};


2) шаблон счетчика
typedef unsigned long serial_t;

template< class T >
class CSerialNumber
{
public:
  typedef T Base; // пригодится :)


private:
  static serial_t next()
  {
    static serial_t next_ = 0;
    // заначим статическую переменную здесь
    // - чтобы не определять за пределами шаблонного класса

    return ++next_;
  }

  serial_t serial_;

public:
  CSerialNumber() : serial_(next()) {}

  CSerialNumber(CSerialNumber const& src) : serial_(next()) {}
  // сквозная нумерация. никаких копий!

  void operator =(CSerialNumber const& src) {}
  // ничего не делать

  serial_t serial() const { return serial_; }
};


Каждый объект каждого считаемого класса должен или наследоваться от счетчика, или содержать его.
При этом, в случае наследования, наблюдается очень интересное явление: один и тот же объект может сосчитаться в разных "каталогах".
В общем-то, это правильно...

Чтобы избежать такого, придется повыделываться.
class CCountedBase
{
private:
  std::string class_;
  serial_t    serial_;

  void set_next()
  {
    static CSerialNuberTable table_; // к примеру, так
    serial_ = table.next(class_);
  }
public:
  std::string const& classname() const { return class_; }
  serial_t serial() const { return serial_; }

public:
  // Заметьте: нет конструктора без параметров. Так надо!

  CCountedBase(const char* s)
  : class_(s)
  { set_next(); }

  CCountedBase(std::string const& s)
  : class_(s)
  { set_next(); }

private: // Конструктор копирования - спрятан. От греха подальше.
  CCounterBase(CCounterBase const& src)
  : class_(src.class_)
  { set_next(); }

public:
  void operator = (CCounterBase const& src) {}
};

И использовать его:
class A : public CCountedBase
{
  ......
public:
  A() : CCountedBase("A") .....; // явно указываем класс
protected:
  explicit A(const char* cn) : CCountedBase(cn) ......; // передаем имя класса "сверху"
};

class B : public A
{
  ......
public:
  B() : A("B") .....; // явно указываем класс
protected:
  explicit B(const char* cn) : A(cn) .....; // передаем имя класса "сверху вниз"
};

В общем, стоит ли так мучаться — не знаю.

3) Если нужно подсчитать объекты не в момент их конструирования, а позже (и не обязательно все), то сделаем хитрее:
class CObjectBase;

class CObjectTable
{
private:
  typedef std::map<CObjectBase const*, serial_t> obj_table_t;
  obj_table_t objects_;

  CSerialNumberTable numbers_;

public:
  serial_t index(CObjectBase const* ptr)
  {
    obj_table_t::iterator it = objects_.find(ptr);
    if(it == objects_.end())
      objects_[ptr] = numbers_.next_ptr(ptr);
    // можно сделать через insert - но так понятнее

    return objects_[ptr];
  }

  void reset(CObjectBase const* ptr)
  {
    objects_.erase(ptr);
  }
};


class CObjectBase
{
  static CObjectTable table_;

public:
  virtual ~CObjectBase() { table_.reset(this); }

  serial_t serial() const { return table_.index(this); } // инициализируется по первому запросу
};
Перекуём баги на фичи!
Re[2]: Счетчик объектов
От: matrixman  
Дата: 21.01.03 12:15
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:


AV>
AV>instances<A>::value = 0;
AV>instances<B>::value = 0;

AV>

Кстати, это не проходит
Re: Счетчик объектов
От: ssm Россия  
Дата: 22.01.03 08:12
Оценка:
Здравствуйте, matrixman, Вы писали:

На самом деле, важно понимать, что все предложенные способы нерешают твоей задачи в полной мере, т.к. предоставляют информацию о создании/разрушении подобъекта твоего объекта(неважно реализовано это делегированием или закрытым наследованием) а не самого объекта. Очень часто этого оказываеться вполне достаточно, но невсегда...
Проблема заключаеться в возможной генерации исключения в теле твоего конструктора при уже созданом подъобъекте

class A : private Counter<A>{
public:
  A(){
    //1
    throw "ups!";
  }
};

...

int main(){
  try{
    A a;
  }
  catch(...){
    //2
  }
}


в точке 1 мы имеем один созданый Counter<A>, но ноль A
в точке 2 мы имеем один созданый Counter<A> и один удаленный Counter<A>, но ноль A
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.