First drop of aptitude for Maemo
[aptitude] / README.SMART-POINTERS
1   Smart pointers in aptitude
2
3
4
5   aptitude uses smart pointers in a number of ways internally.  These
6 techniques generally simplify the code and make it easy to program
7 safely, but C++ being what it is, you should be aware of how they work
8 and what the caveats are.
9
10   * threading
11
12   As of this writing, none of the smart pointers lock their reference
13   counts (implementing locks in the imm::wtree class caused the
14   problem resolver's running time to increase by 50%!).  Some of the
15   less-commonly-used ones may get locking in the future, but for the
16   time being you should handle objects that are given to another
17   thread carefully -- do deep copies of anything that's
18   reference-counted.  (this is only the imm::* stuff at the moment, so
19   the problem is managable) For more information on threading, see
20   README.THREADS.
21
22   * reference-counted immutable values
23
24   aptitude employs reference-counting of immutable objects in several
25   places.  For the most part this is invisible to clients; the typical
26   implementation looks like this:
27
28       class foo
29       {
30         class foo_impl
31         {
32           ...
33         public:
34           void m1();
35           void m2(int);
36           ...
37         };
38       public:
39         void m1();
40         void m2(int);
41         ...
42       };
43
44   When you create a new "foo" object, a corresponding foo_impl is
45   created with reference-count 1.  Reference counts are managed
46   in all the ways you expect, and the object is deleted when you're
47   done with it.
48
49   This use of reference-counting can be viewed as a performance hack:
50   since the objects are immutable, pass-by-value is indistinguishable
51   from pass-by-reference; if we can prove that no strong cycles will
52   be created, it's always safe to reference-count objects like this.
53
54
55   * auto_ptr for temporary return values
56
57   When building up a temporary return value, several routines use
58   auto_ptrs to store intermediates:
59
60       auto_ptr<T> v1 = parse_T_from_string(str1);
61       auto_ptr<T> v2 = parse_T_from_string(str2);
62
63   The advantage here is that you can freely throw exceptions and/or
64   break out of the function with an early "return" without worrying
65   about which of {v1,v2} have to be deleted.  To actually return them,
66   you'd do something like this:
67
68       return pair<T*,T*>(v1.release(), v2.release());
69
70   The "release" calls tell v1 and v2 that they no longer "own" their
71   respective pointers.
72
73
74
75   * reference-counting of display widgets
76
77   Display widgets are also reference-counted.  This is a
78   generalization of the idea that "the enclosing widget owns this
79   one"; it provides more support for extending the lifetime of a
80   widget if, for instance, you want to extract values from it after
81   its parent is done with it.  Unfortunately, this reference counting
82   is NOT fully transparent, and you should be aware of some basic
83   principles:
84
85     - As with any reference counting scheme, it is up to you to
86       avoid creating strong cycles.  By default, the only
87       non-transient strong references are references from a parent to
88       a child; your best bet is to ensure that all additional strong
89       references either have stack lifetime or do not close cycles.
90
91       If you must create a cycle, make sure it gets explicitly broken
92       before all external references to it are lost.
93
94     - Reference-counting is done via the generic ref_ptr class
95       (ref_ptr.h).  This is a templated class, like auto_ptr, and
96       generally works as you expect.  To enforce the use of ref_ptr,
97       all widget constructors are protected; static ::create methods
98       are provided to actually allocate a new widget.  Because the
99       cwidget::widget class initializes its reference count to 1, the
100       ::create method should explicitly decref() its return value; see
101       the existing ::create routines for examples.
102
103       To make code a bit more readable, adopt the convention of
104       creating typedefs for ref_ptr wrappers around new classes.  For
105       instance, if you have just created the class vs_moo, add the
106       following line to its header file:
107
108           typedef ref_ptr<vs_moo> vs_moo_ref;
109
110     - Watch out for deletion of "this".  If you aren't sure whether
111       "this" will be deleted in a method, I recommend creating a
112       method-scoped strong reference to it:
113
114           ref_ptr<this_type> thisref = this;
115
116       Doing so will prevent "this" from being deleted until the
117       current method terminates and is probably good practice in
118       general.
119
120     - Beware sigc::bind.  sigc::bind is an easy way to create bad
121       circularities; moreover, it's actually unsafe to bind a ref_ptr
122       as a slot argument.  The solution adopted in cwidget is to
123       exploit sigc++ weak references.  If w is a ref_ptr, then rather
124       than closing w, you should close over w.weak_ref().
125
126       Unfortunately, w.weak_ref() will appear to the callee as a C++
127       reference, not a ref_ptr: if w has type T, you need a slot that
128       accepts a T&, not a ref_ptr<T>.  To solve this problem, it is
129       conventional for widgets defining public interfaces that accept
130       a ref_ptr<T> to define a corresponding _bare method that accepts
131       a T&; the _bare method should simply instantiate a ref_ptr and
132       call the main interface.  For instance,
133
134           void add_widget(const ref_ptr<cwidget::widget> &w);
135           void add_widget_bare(cwidget::widget &w)
136           {
137             add_widget(ref_ptr<cwidget::widget>(&w));
138           }
139
140       Obviously this is less than ideal, but it will work.  Be aware,
141       though, that the bound argument is a *weak* reference: if there
142       are no strong references to a bound widget, the signal
143       connection will simply disappear.