33
44Sample use case:
55
6- - you want a dynamic array a dynmically allocated derived class
6+ - you want a dynamic array a dynamically allocated derived class
77- thus you have to use pointers for polymorphism. Otherwise objects can have different sizes, and arrays can't be used.
88- how to prevent memory leaks?
99
@@ -21,6 +21,7 @@ lifetime of objects, and release them immediately when they are done.
2121class Base {
2222 public:
2323 static int count;
24+ Base () : Base(0 ) {}
2425 Base (int i) : i(i) {
2526 count++;
2627 }
@@ -29,60 +30,76 @@ class Base {
2930 }
3031 int i;
3132};
32-
3333int Base::count = 0 ;
3434
35- /* No memory leaked. Destructors called. */
36- void unique_ptr_test () {
37- std::vector<std::unique_ptr<Base>> bases;
38- for (int i = 0 ; i < 10 ; ++i) {
39- bases.push_back (std::unique_ptr<Base>(new Base (i)));
40- }
41- }
42-
43- /* Memory leak. Destructors never called. */
44- void raw_ptr_test () {
45- std::vector<Base *> bases;
46- for (int i = 0 ; i < 10 ; ++i) {
47- bases.push_back (new Base (i));
48- }
49- }
50-
51- void manual_ptr_test () {
52- std::vector<Base *> bases;
53- for (int i = 0 ; i < 10 ; ++i) {
54- bases.push_back (new Base (i));
55- }
56- for (auto base : bases) {
57- delete base;
58- }
59- }
60-
6135// Create unique pointer dynamically,
6236// and transfers ownership to caller.
6337std::unique_ptr<Base> return_unique_ptr () {
6438 return std::unique_ptr<Base>(new Base (1 ));
6539}
6640
6741int main () {
68- /* Basic example. */
69- assert (Base::count == 0 );
70- unique_ptr_test ();
71- assert (Base::count == 0 );
72- raw_ptr_test ();
73- assert (Base::count == 10 );
74- manual_ptr_test ();
75- assert (Base::count == 10 );
76-
77- // ERROR: Convert to raw pointer.
78- // Not possible, the cast operator is not defined.
42+ /* Basic examples. */
43+ {
44+ // This is the problem case that we are trying to solve: memory leaks
45+ {
46+ {
47+ Base *base = new Base (1 );
48+ assert (base->i == 1 );
49+ assert (Base::count == 1 );
50+ // You will forget to do this one day.
51+ // delete base;
52+ }
53+ // Then base is lost forever: it went out of scope.
54+ // And the memory has leaked.
55+ assert (Base::count == 1 );
56+ // Hack up the count for future tests.
57+ Base::count = 0 ;
58+ }
59+
60+ // This is how unique_ptr solves it.
61+ {
62+ {
63+ std::unique_ptr<Base> base (new Base (1 ));
64+ assert (base->i == 1 );
65+ assert (Base::count == 1 );
66+ }
67+ // Destructor called automatically! No memory leaks!
68+ assert (Base::count == 0 );
69+ }
70+
71+ }
72+
73+ /* More commonly, the pointers are inside another container.
74+ * When the parent goes out of scope, it just calls the
75+ * child constructors in the same way.
76+ */
77+ {
78+ {
79+ std::vector<std::unique_ptr<Base>> bases;
80+ bases.push_back (std::unique_ptr<Base>(new Base (0 )));
81+ bases.push_back (std::unique_ptr<Base>(new Base (1 )));
82+ assert (bases[0 ]->i == 0 );
83+ assert (bases[1 ]->i == 1 );
84+ assert (Base::count == 2 );
85+ }
86+ assert (Base::count == 0 );
87+ }
88+
89+ // Convert to raw pointer.
7990 {
8091 std::unique_ptr<int > p (new int );
81- // int *raw = p;
92+ int *raw;
93+
94+ // Not possible, the cast operator is not defined.
95+ // raw = p;
96+
97+ // But can be done explicitly with .get().
98+ raw = p.get ();
8299 }
83100
84101 // Copy constructor is deleted.
85- // This is what imposes uniqueness.
102+ // This imposes uniqueness of ownership .
86103 {
87104 std::unique_ptr<int > p (new int );
88105 // ERROR.
@@ -121,26 +138,42 @@ int main() {
121138 }
122139 }
123140
124- /*
125- # reset
141+ // # reset
142+ {
143+ /* With no argumetns, explicit destruction of pointer. Equivalent to `delete`.
144+ *
145+ * http://stackoverflow.com/questions/25609457/unique-ptr-explicit-delete
146+ */
147+ {
148+ std::unique_ptr<Base> p (new Base (1 ));
149+ assert (Base::count == 1 );
150+ p.reset ();
151+ assert (Base::count == 0 );
152+ }
126153
127- Explicit destruction of pointer. Equivalent to `delete`.
154+ // There is no assignment operator, but reset with an argument
155+ // does what you would expect: release and replace.
156+ {
157+ std::unique_ptr<Base> p (new Base (1 ));
158+ assert (p->i == 1 );
159+ assert (Base::count == 1 );
128160
129- http://stackoverflow.com/questions/25609457/unique-ptr-explicit-delete
130- */
131- {
132- Base::count = 0 ;
133- std::unique_ptr<Base> p = std::unique_ptr<Base>(new Base (1 ));
134- assert (Base::count == 1 );
135- p.reset ();
161+ // Nope.
162+ // p = new Base(2);
163+
164+ // Yup.
165+ p.reset (new Base (2 ));
166+ assert (p->i == 2 );
167+ assert (Base::count == 1 );
168+ }
136169 assert (Base::count == 0 );
137170 }
138171
139172 /*
140- # unique_ptr function argments
173+ # unique_ptr function arguments
141174
142- - transfering ownership TODO
143- - use raw pointeres on the interface, and convert it to unique_ptr inside callee
175+ - transferring ownership TODO examples
176+ - use raw pointers on the interface, and convert it to unique_ptr inside callee
144177 - if you already have an unique_ptr, release() it
145178 - this allows you to not tie down to a specific smart pointer on the function interface
146179 - use unique_ptr on interface and move on caller.
@@ -181,4 +214,19 @@ int main() {
181214 assert (Base::count == 0 );
182215 }
183216#endif
217+
218+ /* Array inside unique_ptr
219+ * https://stackoverflow.com/questions/16711697/is-there-any-use-for-unique-ptr-with-array
220+ */
221+ {
222+ size_t n = 2 ;
223+ Base::count = 0 ;
224+ {
225+ std::unique_ptr<Base[]> array (new Base[n]);
226+ array[0 ].i = 1 ;
227+ array[0 ].i = 1 ;
228+ assert (Base::count == 2 );
229+ }
230+ assert (Base::count == 0 );
231+ }
184232}
0 commit comments