В книге предлагается усовершенствовать класс с AutoCounter, как-то так
Измените класс C16:AutoCounter.h из первого тома так, чтобы он стал действительно полезным средством отладки. Он должен использоваться в качестве вложенного члена каждого класса, который вы планируете трассировать. Оформите AutoCounter в виде шаблона, параметризованного по имени внешнего класса. Во всех сообщениях об ошибках выводите имя класса средствами RTTI.
класс AutoCounter, до:
Кликните здесь для просмотра всего текста
C++ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
| #ifndef AUTOCOUNTER_H
#define AUTOCOUNTER_H
#include"../require.h"
#include<iostream>
#include<set>
#include<string>
class AutoCounter
{
public:
//Объекты могут создаваться только так
static AutoCounter* create()
{
return new AutoCounter();
}
~AutoCounter()
{
std::cout << "destroying[" << id << "]" << std::endl;
verifier.remove(this);
}
//Вывод объекто и указателей
friend std::ostream& operator<<(std::ostream& os, const AutoCounter& a)
{
return os << "AutoCounter " << ac.id;
}
friend std::ostream& operator<<(std::ostream& os, const AutoCounter* a)
{
return os << "AutoCounter " << ac->id;
}
private:
static int count;
int id;
class CleanupCheck
{
public:
void add(AutoCounter* ap)
{
trace.insert(ap);
}
void remove(AutoCounter* ap)
{
require(trace.erase(ap) == 1, "Attempt to delete AutoCounter twice");
}
~CleanupCheck()
{
std::cout << "~CleanupCheck()" << std::endl;
require(trace.size() == 0, "All AutoCounter objects not cleaned up");
}
private:
std::set<AutoCounter*> trace;
};
static CleanupCheck verifier;
AutoCounter():id(count++)
{
verifier.add(this); //Register itself
std::cout << "created[" << id << "]" << std::endl;
}
//Запретить присваивание и конструктор копирования
AutoCounter(const AutoCounter&);
AutoCounter operator=(const AutoCounter&);
};
#endif
//AutoCounter.cpp
#include "AutoCounter.h"
AutoCounter::CleanupCheck AutoCounter::verifier; //что за инициализация такая хитрая.
int AutoCounter::count = 0; |
|
Усовершенствования это что-то вроде этого:
Кликните здесь для просмотра всего текста
C++ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
| #ifndef AUTOCOUNTER_H
#define AUTOCOUNTER_H
#include"../_eckel/recuire.h"
#include<iostream>
#include<set>
#include<string>
#include<typeinfo>
template<typename T>
class AutoCounter
{
public:
//Объекты могут создаваться только так
static AutoCounter<T>* create()
{
return new AutoCounter<T>();
}
~AutoCounter()
{
std::cout << "destroying[" << id << "]" << std::endl;
verifier.remove(this);
}
//Вывод объектов и указателей
template<typename T>
friend std::ostream& operator<<(std::ostream& os, const AutoCounter<T>& a)
{
return os << "AutoCounter " << a.id << '\t' << typeid(a.className);
}
template<typename T>
friend std::ostream& operator<<(std::ostream& os, const AutoCounter<T>* a)
{
return os << "AutoCounter " << a->id << '\t' << typeid(a->className);
}
private:
static int count;
int id;
T className;
class CleanupCheck
{
public:
void add(AutoCounter* ap)
{
trace.insert(ap);
}
void remove(AutoCounter* ap)
{
require(trace.erase(ap) == 1, "Attempt to delete AutoCounter twice");
}
~CleanupCheck()
{
std::cout << "~CleanupCheck()" << std::endl;
require(trace.size() == 0, "All AutoCounter objects not cleaned up");
}
private:
std::set<AutoCounter*> trace;
};
static CleanupCheck verifier;
AutoCounter() :id(count++)
{
verifier.add(this); //Register itself
std::cout << "created[" << id << "]" << std::endl;
}
//Запретить присваивание и конструктор копирования
AutoCounter(const AutoCounter&);
AutoCounter& operator=(const AutoCounter&);
};
template<typename T>
int AutoCounter<T>::count = 0;
#endif
//...... |
|
Получается, что этот класс, по сути, является абстрактным, тогда как создаваться объекты внутри других классов, которые собираешься трассировать?! Возможно ли и правильно ли поступить так, вынести конструктор по умолчанию в открытую область класса. Если параметризируется по типу класса, возможно, стоит удалить static int count и int id, если предлагается в отладочный вывод включать имя объекта/класса?
Добавлено через 1 час 28 минут
Хз... Но, думаю, вопрос можно удалять.