aboutsummaryrefslogtreecommitdiff
path: root/doc/smart_pointer_usage.md
blob: 5f7701327d3422f877261a2f20f2aa268e65d797 (plain)
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
Usage of smart pointers in sfntly C++ port
=========================================================================================================================================================

In sfntly C++ port, an object ref-counting and smart pointer mechanism
is implemented. The implementation works very much like COM.

Ref-countable object type inherits from RefCounted<>, which have
addRef() and release() just like IUnknown in COM (but no
QueryInterface). Ptr<> is a smart pointer class like
CComPtr<> which is used to hold the ref-countable objects so that
the object ref count is handled correctly.

Lets take a look at the example:

``` {.prettyprint}
class Foo : public RefCounted<Foo> {
 public:
  static Foo* CreateInstance() {
    Ptr<Foo> obj = new Foo();  // ref count = 1
    return obj.detach();  // Giving away the control of this instance.
  }
};
typedef Ptr<Foo> FooPtr;  // Common short-hand notation.

FooPtr obj;
obj.attach(Foo::CreateInstance());  // ref count = 1
                                    // Take over control but not bumping
                                    // ref count.
{
  FooPtr obj2 = obj;  // ref count = 2
                      // Assignment bumps up ref count.
}  // ref count = 1
   // obj2 out of scope, decrements ref count

obj.release();  // ref count = 0, object destroyed
```

Notes on usage
---------------------------------------------------------------------

-   Virtual inherit from RefCount interface in base class if smart
    pointers are going to be defined.

<!-- -->

-   All RefCounted objects must be instantiated on the heap. Allocating
    the object on stack will cause crash.

<!-- -->

-   Be careful when you have complex inheritance. For example,

> In this case the smart pointer is pretty dumb and dont count on it to
> nicely destroy your objects as designed. Try refactor your code like
>
> ``` {.prettyprint}
> class I;  // the common interface and implementations
> class A : public I, public RefCounted<A>;  // A specific implementation
> class B : public I, public RefCounted<B>;  // B specific implementation
> ```

-   Smart pointers here are very bad candidates for function parameters
    and return values. Use dumb pointers when passing over the stack.

<!-- -->

-   When down\_cast is performed on a dangling pointer due to bugs in
    code, VC++ will generate SEH which is not handled well in VC++
    debugger. One can use WinDBG to run it and get the faulting stack.

<!-- -->

-   Idioms for heap object as return value

> If you are not passing that object back, you are the end of scope.

> Be very careful when using the assignment operator as opposed to
> attaching. This can easily cause memory leaks. Have a look at [The
> difference between assignment and attachment with ATL smart
> pointers](http://blogs.msdn.com/b/oldnewthing/archive/2009/11/20/9925918.aspx).
> Since were using essentially the same model, it applies in pretty much
> the same way. The easiest way of knowing when to Attach and when to
> assign is to check the declaration of the function you are using.
>
> ``` {.prettyprint}
>   // Attach to the pointer returned by GetInstance
>   static CALLER_ATTACH FontFactory* GetInstance();
>
>   // Assign pointer returned by NewCMapBuilder 
>   CMap::Builder* NewCMapBuilder(const CMapId& cmap_id,
>                                 ReadableFontData* data);
> ```

Detecting Memory Leak
------------------------------------------------------------------------------------------

> The implementation of COM-like ref-counting and smart pointer remedies
> the lack of garbage collector in C++ to certain extent, however, it
> also introduces other problems. The most common one is memory leakage.
> How do we know that our code leak memory or not?

-   For Linux/Mac, valgrind
    [http://valgrind.org](http://valgrind.org/)
    is very useful.
-   For Windows, the easiest is to use Visual C++ built-in CRT debugging
    [http://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.80).aspx](http://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.80).aspx)

Useful Tips for Debugging Ref-Couting Issue
------------------------------------------------------------------------------------------------------------------------------------------------------------

-   Define `ENABLE_OBJECT_COUNTER` and `REF_COUNT_DEBUGGING`. All
    ref-count related activity will be ouput to stderr.

<!-- -->

-   The logs will look like (under VC2010)

> Use your favorite editor to transform them into SQL statements, e.g.
> Regex pattern
>
> ``` {.prettyprint}
> ^([ACDR]) class RefCounted<class sfntly::([A-Za-z0-9:]+)>[ *const]+:oc=([-0-9]+),oid=([0-9]+),rc=([-0-9]+)
> ```

> Replace to
>
> ``` {.prettyprint}
> insert into log values(\1, \2, \3, \4, \5);
> ```

-   Add one line to the beginning of log

<!-- -->

-   Run sqlite shell, use .read to input the SQL file.

<!-- -->

-   Run following commands to get the leaking object class and object
    id:

<!-- -->

-   Once you know which object is leaking, its much easier to setup
    conditional breakpoints to identify the real culprit.