DEV Community

MinBapE
MinBapE

Posted on

Smart Pointers

Memory Management in C/C++

Unlike languages such as Java that automatically manage memory through a Garbage Collector, C/C++ requires developers to manually allocate and deallocate memory. This means special attention must be paid to memory management. For example, C uses malloc and free to acquire and release memory, while C++ uses new and delete for the same purpose. While this characteristic allows for greater program efficiency, it also introduces risks such as memory leaks and incorrect deallocation. As a result, C/C++ programmers must always be mindful of memory usage, which is one of the key characteristics of these languages.

// 1. Memory Leak
void memoryLeakExample() {
    int* ptr = new int(42);
    // No delete -> Memory leak
}

// 2. Null Pointer Issue
void nullPointerExample() {
    int* ptr = nullptr;
    *ptr = 10;  // Crash!
}

// 3. Dangling Pointer Issue
void danglingPointerExample() {
    int* ptr = new int(42);
    delete ptr;
    *ptr = 10;  // Accessing already freed memory
}
Enter fullscreen mode Exit fullscreen mode

Smart Pointer

Template classes provided in C++ for safe dynamic memory management

Smart pointers wrap raw pointers and automatically manage memory according to the RAII (Resource Acquisition Is Initialization) principle. Memory is allocated when a Smart Pointer object is created, and automatically deallocated when the destructor is called as it goes out of scope. This prevents memory leaks without developers explicitly calling delete.

Types

  • Unique Ptr
    • Has exclusive ownership.
    • Cannot be copied, only move operations are allowed.
    • Has almost no overhead and performs nearly identical to raw pointers.
  void uniquePtrExample() {
      std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
      // std::unique_ptr<int> ptr2 = ptr1;  // Compilation error
      std::unique_ptr<int> ptr2 = std::move(ptr1);  // Only move allowed
  }
Enter fullscreen mode Exit fullscreen mode
  • Shared Ptr
    • Multiple objects can share a single resource.
    • Internally tracks the number of owners through Reference Counting.
    • Memory is deallocated when the last shared_ptr is destroyed.
    • Has slight performance overhead due to Reference Counting management.
    • Circular references with Shared Ptr can cause memory leaks, in which case Weak Ptr should be used.
  void sharedPtrExample() {
      std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
      std::shared_ptr<int> ptr2 = ptr1;  // Copy allowed
      std::cout << ptr1.use_count();  // 2
  }
Enter fullscreen mode Exit fullscreen mode
  • Weak Ptr
    • Used together with Shared Ptr, it's a pointer that only references objects without ownership.
    • Does not increment Reference Counting.
    • Used to resolve circular reference issues between Shared Ptr.
    • lock() returns a Shared Ptr if the object is still alive, or nullptr if already destroyed.
  void weakPtrExample() {
      std::shared_ptr<int> shared = std::make_shared<int>(42);
      std::weak_ptr<int> weak = shared;  // No reference count increment

      if (auto ptr = weak.lock()) {  // Convert to shared_ptr
          std::cout << *ptr;
      }
  }
Enter fullscreen mode Exit fullscreen mode

Conclusion

Smart pointers are essential tools for modern C++ programming. They help prevent common memory management issues while maintaining the performance characteristics that make C++ powerful. By understanding and using unique_ptr, shared_ptr, and weak_ptr appropriately, you can write safer and more maintainable code.

Top comments (0)