1/*
2 * Smart Pointers Demo
3 *
4 * Demonstrates:
5 * - unique_ptr: exclusive ownership
6 * - shared_ptr: shared ownership with reference counting
7 * - weak_ptr: breaking circular references
8 * - Custom deleters
9 * - make_unique / make_shared
10 *
11 * Compile: g++ -std=c++20 -Wall -Wextra 03_smart_pointers.cpp -o smart_pointers
12 */
13
14#include <iostream>
15#include <memory>
16#include <vector>
17#include <string>
18
19// ============ Helper Class ============
20class Resource {
21private:
22 std::string name_;
23 int* data_;
24
25public:
26 Resource(const std::string& name) : name_(name) {
27 data_ = new int(42);
28 std::cout << " [Resource '" << name_ << "' created]\n";
29 }
30
31 ~Resource() {
32 delete data_;
33 std::cout << " [Resource '" << name_ << "' destroyed]\n";
34 }
35
36 void use() const {
37 std::cout << " Using resource '" << name_ << "', data=" << *data_ << "\n";
38 }
39
40 std::string get_name() const { return name_; }
41};
42
43// ============ unique_ptr ============
44void demo_unique_ptr() {
45 std::cout << "\n=== unique_ptr (Exclusive Ownership) ===\n";
46
47 // Create unique_ptr with make_unique
48 std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>("unique-1");
49 ptr1->use();
50
51 // Move semantics (transfer ownership)
52 std::cout << "Moving ownership...\n";
53 std::unique_ptr<Resource> ptr2 = std::move(ptr1);
54
55 if (!ptr1) {
56 std::cout << " ptr1 is now nullptr\n";
57 }
58
59 if (ptr2) {
60 std::cout << " ptr2 owns the resource\n";
61 ptr2->use();
62 }
63
64 // Array with unique_ptr
65 std::cout << "\nUnique array:\n";
66 std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
67 for (int i = 0; i < 5; i++) {
68 arr[i] = i * 10;
69 }
70 std::cout << " Array: ";
71 for (int i = 0; i < 5; i++) {
72 std::cout << arr[i] << " ";
73 }
74 std::cout << "\n";
75
76 std::cout << "Exiting demo_unique_ptr scope...\n";
77}
78
79// ============ shared_ptr ============
80void demo_shared_ptr() {
81 std::cout << "\n=== shared_ptr (Shared Ownership) ===\n";
82
83 // Create shared_ptr with make_shared
84 std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>("shared-1");
85 std::cout << " ptr1 use_count: " << ptr1.use_count() << "\n";
86
87 // Copy (share ownership)
88 {
89 std::shared_ptr<Resource> ptr2 = ptr1;
90 std::cout << " ptr1 use_count: " << ptr1.use_count() << "\n";
91 std::cout << " ptr2 use_count: " << ptr2.use_count() << "\n";
92
93 std::shared_ptr<Resource> ptr3 = ptr1;
94 std::cout << " ptr1 use_count: " << ptr1.use_count() << "\n";
95
96 std::cout << " Exiting inner scope...\n";
97 }
98
99 std::cout << " ptr1 use_count after scope: " << ptr1.use_count() << "\n";
100 ptr1->use();
101
102 std::cout << "Exiting demo_shared_ptr scope...\n";
103}
104
105// ============ weak_ptr (Breaking Cycles) ============
106class Node {
107public:
108 std::string name;
109 std::shared_ptr<Node> next;
110 std::weak_ptr<Node> prev; // weak_ptr to avoid cycle
111
112 Node(const std::string& n) : name(n) {
113 std::cout << " [Node '" << name << "' created]\n";
114 }
115
116 ~Node() {
117 std::cout << " [Node '" << name << "' destroyed]\n";
118 }
119};
120
121void demo_weak_ptr() {
122 std::cout << "\n=== weak_ptr (Breaking Circular References) ===\n";
123
124 std::shared_ptr<Node> node1 = std::make_shared<Node>("A");
125 std::shared_ptr<Node> node2 = std::make_shared<Node>("B");
126
127 // Create doubly-linked list
128 node1->next = node2;
129 node2->prev = node1; // weak_ptr: doesn't increment ref count
130
131 std::cout << " node1 use_count: " << node1.use_count() << "\n";
132 std::cout << " node2 use_count: " << node2.use_count() << "\n";
133
134 // Access weak_ptr through lock()
135 if (auto prev = node2->prev.lock()) {
136 std::cout << " node2's prev: " << prev->name << "\n";
137 }
138
139 std::cout << "Exiting demo_weak_ptr scope...\n";
140}
141
142// ============ Custom Deleter ============
143struct FileCloser {
144 void operator()(FILE* fp) const {
145 if (fp) {
146 std::cout << " [Custom deleter: closing file]\n";
147 fclose(fp);
148 }
149 }
150};
151
152void demo_custom_deleter() {
153 std::cout << "\n=== Custom Deleter ===\n";
154
155 // unique_ptr with custom deleter
156 {
157 std::unique_ptr<FILE, FileCloser> file(fopen("/tmp/test.txt", "w"));
158 if (file) {
159 fprintf(file.get(), "Hello from custom deleter!\n");
160 std::cout << " File written\n";
161 }
162 std::cout << " Exiting scope...\n";
163 }
164 std::cout << " File automatically closed by custom deleter\n";
165
166 // shared_ptr with custom deleter (lambda)
167 {
168 std::shared_ptr<Resource> ptr(
169 new Resource("custom-delete"),
170 [](Resource* r) {
171 std::cout << " [Lambda deleter called]\n";
172 delete r;
173 }
174 );
175 ptr->use();
176 std::cout << " Exiting scope...\n";
177 }
178}
179
180// ============ Container of Smart Pointers ============
181void demo_container() {
182 std::cout << "\n=== Container of Smart Pointers ===\n";
183
184 std::vector<std::unique_ptr<Resource>> resources;
185
186 resources.push_back(std::make_unique<Resource>("resource-1"));
187 resources.push_back(std::make_unique<Resource>("resource-2"));
188 resources.push_back(std::make_unique<Resource>("resource-3"));
189
190 std::cout << "Using all resources:\n";
191 for (const auto& res : resources) {
192 res->use();
193 }
194
195 std::cout << "Clearing container...\n";
196 resources.clear();
197 std::cout << "All resources destroyed\n";
198}
199
200// ============ Polymorphism with Smart Pointers ============
201class Shape {
202public:
203 virtual ~Shape() = default;
204 virtual void draw() const = 0;
205};
206
207class Circle : public Shape {
208public:
209 void draw() const override {
210 std::cout << " Drawing Circle\n";
211 }
212};
213
214class Rectangle : public Shape {
215public:
216 void draw() const override {
217 std::cout << " Drawing Rectangle\n";
218 }
219};
220
221void demo_polymorphism() {
222 std::cout << "\n=== Polymorphism with Smart Pointers ===\n";
223
224 std::vector<std::unique_ptr<Shape>> shapes;
225 shapes.push_back(std::make_unique<Circle>());
226 shapes.push_back(std::make_unique<Rectangle>());
227 shapes.push_back(std::make_unique<Circle>());
228
229 std::cout << "Drawing all shapes:\n";
230 for (const auto& shape : shapes) {
231 shape->draw();
232 }
233}
234
235// ============ Main ============
236int main() {
237 std::cout << "Smart Pointers Demo\n";
238 std::cout << "===================\n";
239
240 demo_unique_ptr();
241 demo_shared_ptr();
242 demo_weak_ptr();
243 demo_custom_deleter();
244 demo_container();
245 demo_polymorphism();
246
247 std::cout << "\nAll demos completed!\n";
248 return 0;
249}