03_smart_pointers.cpp

Download
cpp 250 lines 6.5 KB
  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}