object.h 4.94 KB
Newer Older
Wenzel Jakob's avatar
Wenzel Jakob committed
1
2
3
4
#if !defined(__OBJECT_H)
#define __OBJECT_H

#include <atomic>
5
#include "constructor-stats.h"
Wenzel Jakob's avatar
Wenzel Jakob committed
6
7
8
9
10

/// Reference counted object base class
class Object {
public:
    /// Default constructor
11
    Object() { print_default_created(this); }
Wenzel Jakob's avatar
Wenzel Jakob committed
12
13

    /// Copy constructor
14
    Object(const Object &) : m_refCount(0) { print_copy_created(this); }
Wenzel Jakob's avatar
Wenzel Jakob committed
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

	/// Return the current reference count
	int getRefCount() const { return m_refCount; };

	/// Increase the object's reference count by one
	void incRef() const { ++m_refCount; }

	/** \brief Decrease the reference count of
	 * the object and possibly deallocate it.
	 *
	 * The object will automatically be deallocated once
	 * the reference count reaches zero.
	 */
	void decRef(bool dealloc = true) const {
	    --m_refCount;
	    if (m_refCount == 0 && dealloc)
            delete this;
        else if (m_refCount < 0)
	        throw std::runtime_error("Internal error: reference count < 0!");
    }

    virtual std::string toString() const = 0;
protected:
	/** \brief Virtual protected deconstructor.
	 * (Will only be called by \ref ref)
	 */
41
	virtual ~Object() { print_destroyed(this); }
Wenzel Jakob's avatar
Wenzel Jakob committed
42
43
44
45
private:
    mutable std::atomic<int> m_refCount { 0 };
};

46
47
48
49
50
51
// Tag class used to track constructions of ref objects.  When we track constructors, below, we
// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
// ref_tag.  This lets us check that the total number of ref<Anything> constructors/destructors is
// correct without having to check each individual ref<Whatever> type individually.
class ref_tag {};

Wenzel Jakob's avatar
Wenzel Jakob committed
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * \brief Reference counting helper
 *
 * The \a ref refeference template is a simple wrapper to store a
 * pointer to an object. It takes care of increasing and decreasing
 * the reference count of the object. When the last reference goes
 * out of scope, the associated object will be deallocated.
 *
 * \ingroup libcore
 */
template <typename T> class ref {
public:
	/// Create a nullptr reference
65
    ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
Wenzel Jakob's avatar
Wenzel Jakob committed
66
67
68
69

    /// Construct a reference from a pointer
	ref(T *ptr) : m_ptr(ptr) {
	    if (m_ptr) ((Object *) m_ptr)->incRef();
70
71
72

        print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");

Wenzel Jakob's avatar
Wenzel Jakob committed
73
74
75
76
77
78
	}

	/// Copy constructor
    ref(const ref &r) : m_ptr(r.m_ptr) {
        if (m_ptr)
            ((Object *) m_ptr)->incRef();
79
80

        print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
Wenzel Jakob's avatar
Wenzel Jakob committed
81
82
83
84
85
    }

    /// Move constructor
    ref(ref &&r) : m_ptr(r.m_ptr) {
        r.m_ptr = nullptr; 
86
87

        print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
Wenzel Jakob's avatar
Wenzel Jakob committed
88
89
90
91
92
93
    }

    /// Destroy this reference
    ~ref() {
        if (m_ptr)
            ((Object *) m_ptr)->decRef();
94
95

        print_destroyed(this); track_destroyed((ref_tag*) this);
Wenzel Jakob's avatar
Wenzel Jakob committed
96
97
98
99
    }

    /// Move another reference into the current one
	ref& operator=(ref&& r) {
100
101
        print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);

Wenzel Jakob's avatar
Wenzel Jakob committed
102
103
104
105
106
107
108
109
110
111
112
		if (*this == r)
			return *this;
		if (m_ptr)
			((Object *) m_ptr)->decRef();
		m_ptr = r.m_ptr;
		r.m_ptr = nullptr;
		return *this;
	}

	/// Overwrite this reference with another reference
	ref& operator=(const ref& r) {
113
114
        print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);

Wenzel Jakob's avatar
Wenzel Jakob committed
115
116
117
118
119
120
121
122
123
124
125
126
		if (m_ptr == r.m_ptr)
			return *this;
		if (m_ptr)
			((Object *) m_ptr)->decRef();
		m_ptr = r.m_ptr;
		if (m_ptr)
			((Object *) m_ptr)->incRef();
		return *this;
	}

	/// Overwrite this reference with a pointer to another object
	ref& operator=(T *ptr) {
127
128
        print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");

Wenzel Jakob's avatar
Wenzel Jakob committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
		if (m_ptr == ptr)
			return *this;
		if (m_ptr)
			((Object *) m_ptr)->decRef();
		m_ptr = ptr;
		if (m_ptr)
			((Object *) m_ptr)->incRef();
		return *this;
	}

	/// Compare this reference with another reference
	bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }

	/// Compare this reference with another reference
	bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }

	/// Compare this reference with a pointer
	bool operator==(const T* ptr) const { return m_ptr == ptr; }

	/// Compare this reference with a pointer
	bool operator!=(const T* ptr) const { return m_ptr != ptr; }

	/// Access the object referenced by this reference
	T* operator->() { return m_ptr; }

	/// Access the object referenced by this reference
	const T* operator->() const { return m_ptr; }

	/// Return a C++ reference to the referenced object
	T& operator*() { return *m_ptr; }

	/// Return a const C++ reference to the referenced object
	const T& operator*() const { return *m_ptr; }

	/// Return a pointer to the referenced object
	operator T* () { return m_ptr; }

	/// Return a const pointer to the referenced object
	T* get() { return m_ptr; }

	/// Return a pointer to the referenced object
	const T* get() const { return m_ptr; }
private:
	T *m_ptr;
};

#endif /* __OBJECT_H */