-
Notifications
You must be signed in to change notification settings - Fork 30
/
Pointer.h
200 lines (176 loc) · 6.35 KB
/
Pointer.h
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* \file IMP/Pointer.h
* \brief A nullptr-initialized pointer to an \imp Object.
*
* Copyright 2007-2022 IMP Inventors. All rights reserved.
*
*/
#ifndef IMPKERNEL_POINTER_H
#define IMPKERNEL_POINTER_H
#include <IMP/kernel_config.h>
#include "internal/PointerBase.h"
#include "WeakPointer.h"
IMPKERNEL_BEGIN_NAMESPACE
//! A smart pointer to a reference counted object
/** Any time you store an Object in a C++ program, you should use a
Pointer, rather than a raw C++ pointer (or PointerMember, if the pointer
is stored in a class). Using a pointer manages
the reference counting and makes sure that the object is not deleted
prematurely when, for example, all Python references go away and
that it is deleted properly if an exception is thrown during the
function.
Use the IMP_NEW() macro to aid creation of pointers to new objects.
For example, when implementing a Restraint that uses a
PairScore, store the PairScore like this:
\code
PointerMember<PairScore> ps_;
\endcode
When creating Object instances in C++, you should write code like:
\code
em::FitRestraint* create_fit_restraint(std::string mapname,
const ParticlesTemp &ps)
{
IMP_NEW(core::LeavesRefiner, lr, (atom::Hierarchy::get_traits()));
Pointer<em::DensityMap> map= em::read_map("file_name.mrc");
IMP_NEW(em::FitRestraint, fr, (ps, map, lr));
return fr.release();
}
\endcode
which is equivalent to
\code
IMP::em::FitRestraint* create_fit_restraint(std::string mapname,
const ParticlesTemp
&ps)
{
Pointer<core::LeavesRefiner> lr
= new core::LeavesRefiner(atom::Hierarchy::get_traits());
Pointer<IMP::em::DensityMap> map
= em::read_map("file_name.mrc");
Pointer<em::FitRestraint> fr
= new em::FitRestraint(ps, map, lr));
return fr.release();
}
\endcode
There are several important things to note in this code:
- the use of Pointer::release() on the return. Otherwise, when the
reference counted pointer goes out of scope, it will unref the
em::FitRestraint, notice the count is 0, and delete it, before
passing the (now invalid) pointer back to the calling function
- the use of reference counted pointers everywhere. This ensures
that if, for example, em::read_map() throws an exception since the
file name is invalid, the core::LeavesRefiner will be deleted
properly.
\note Do not pass Pointers as arguments to functions; pass raw C++
pointers instead.
\note Consider using IMP::PointerMember when storing pointers to
ref-counted objects as class members (the only difference is that
the object will be marked by the pointer as 'used')
\note Use IMP::WeakPointer to break cycles or to point to
non-ref-counted objects.
\param[in] O The type of RefCounted-derived object to point to
\see PointerMember
\see WeakPointer
\see UncheckedWeakPointer
*/
template <class O>
struct Pointer
: IMP::internal::PointerBase<IMP::internal::RefCountedPointerTraits<O> > {
typedef IMP::internal::PointerBase<IMP::internal::RefCountedPointerTraits<O> > P;
template <class Any>
Pointer(const Any& o)
: P(o) {}
Pointer() {}
template <class OT>
Pointer<O>& operator=(const IMP::internal::PointerBase<OT>& o) {
P::operator=(o);
return *this;
}
template <class OT>
Pointer<O>& operator=(OT* o) {
P::operator=(o);
return *this;
}
Pointer<O>& operator=(std::nullptr_t o) {
P::operator=(o);
return *this;
}
Pointer<O>& operator=(const P& o) {
P::operator=(o);
return *this;
}
#ifdef IMP_DOXYGEN
//! Relinquish control of the raw pointer stored in the Pointer
/** Use this to safely return objects allocated within functions.
The reference count of the object will be decreased by one,
but even it it becomes 0, the object will not be destroyed.
@return a valid raw pointer to the object stored in Pointer
*/
O* release();
//! get the raw pointer to the object
O* get() const;
#endif
};
//! A smart pointer to a ref-counted Object that is a class member
/** This class is identical
to Pointer, but in addition, Object::set_was_used(true) will be called so
you don't get warnings about unused objects once the object is stored in the
owning class.
@note The object being pointed to must inherit from IMP::Object.
\param[in] O The type of IMP::RefCounted-derived object to point to
\see Pointer
\see WeakPointer
\see UncheckedWeakPointer
*/
template <class O>
struct PointerMember
: IMP::internal::PointerBase<IMP::internal::PointerMemberTraits<O> > {
typedef IMP::internal::PointerBase<IMP::internal::PointerMemberTraits<O> > P;
template <class Any>
PointerMember(const Any& o)
: P(o) {}
PointerMember() {}
template <class OT>
PointerMember<O>& operator=(const IMP::internal::PointerBase<OT>& o) {
P::operator=(o);
return *this;
}
template <class OT>
PointerMember<O>& operator=(OT* o) {
P::operator=(o);
return *this;
}
PointerMember<O>& operator=(std::nullptr_t o) {
P::operator=(o);
return *this;
}
PointerMember<O>& operator=(const P& o) {
P::operator=(o);
return *this;
}
#ifdef IMP_DOXYGEN
//! Relinquish control of the raw pointer stored in the PointerMember
/** Use this to safely return objects allocated within functions.
The reference count of the object will be decreased by one,
but even it it becomes 0, the object will not be destroyed.
@return a valid raw pointer to the object stored in the PointerMember
*/
O* release();
//! get the raw pointer to the object
O* get() const;
#endif
};
/******* streaming ********/
#if !defined(IMP_DOXYGEN) && !defined(SWIG)
template <class T>
inline std::ostream& operator<<(std::ostream& out, Pointer<T> o) {
out << Showable(o.get());
return out;
}
template <class T>
inline std::ostream& operator<<(std::ostream& out, PointerMember<T> o) {
out << Showable(o.get());
return out;
}
#endif
IMPKERNEL_END_NAMESPACE
#endif /* IMPKERNEL_POINTER_H */