C++ PROGRAMMING ยท 15 MIN STUDY

Dynamic memory, RAII, and smart pointers

Understand dynamic object lifetime, ownership, RAII, and modern C++ smart pointers.

Learning objectives

  • Distinguish automatic and dynamic object lifetime.
  • Explain why manual new/delete is error-prone.
  • Describe RAII and ownership.
  • Choose between unique_ptr, shared_ptr, and weak_ptr at a basic level.

Prerequisites: understand pointers, classes, constructors and destructors, and object lifetime. Review Pointers, Classes and objects, Constructors and destructors, and Scope and lifetime first. Examples use C++17.

Why dynamic lifetime?

Some objects need to live beyond the block in which they were created, or their number is only known while the program runs. C++ supports dynamic storage, but manually managing it creates responsibility: every successful allocation must be released exactly once, and no pointer may be used after the object is destroyed.

Manual allocation: understand, but do not prefer

#include <iostream>\nint* value = new int{42};
std::cout << *value << '\n';
delete value;
value = nullptr;

new creates an object with dynamic storage duration and returns a pointer. delete ends that object's lifetime and releases its storage. Forgetting delete can leak memory; deleting twice or using a pointer afterward is also wrong. This syntax is important to understand, but modern C++ normally uses resource-managing types instead.

RAII: let object lifetime manage resources

RAII means Resource Acquisition Is Initialization. A resource is acquired by an object's construction and released by its destructor. The same idea manages memory, files, locks, and other resources. Standard containers such as std::vector already use RAII internally.

Unique ownership with unique_ptr

C++17
#include <iostream>
#include <memory>

int main() {
    auto value = std::make_unique<int>(42);
    std::cout << *value << '\n';
}

std::unique_ptr represents exclusive ownership: one unique_ptr owns the object. When the smart pointer is destroyed, it automatically deletes the object. It cannot be copied, but ownership can be moved.

Shared ownership with shared_ptr

#include <memory>\nauto first = std::make_shared<int>(42);
auto second = first; // shared ownership
// object is destroyed when the last shared owner is gone

std::shared_ptr uses shared ownership. A control block tracks how many shared owners remain. Use it only when the design genuinely requires shared lifetime; reference counting adds cost and can create cycles.

weak_ptr breaks ownership cycles

std::weak_ptr observes an object managed by shared_ptr without increasing the shared ownership count. It is useful for non-owning links that must not keep an object alive, such as parent/child or cache relationships. Call lock() to obtain a temporary shared_ptr if the object still exists.

Ownership rules of thumb

  • Prefer automatic objects and standard containers such as vector and string.
  • Use unique_ptr for one clear owner of a dynamically allocated object.
  • Use shared_ptr only when multiple owners truly share lifetime.
  • Use weak_ptr for a non-owning observation of a shared object.
  • Do not use raw pointers to express ownership unless you are implementing a low-level resource abstraction with a clear contract.

Common mistakes

  • Forgetting to delete manually allocated memory.
  • Deleting an object twice or using it after delete.
  • Creating shared_ptr ownership cycles that prevent destruction.
  • Assuming a raw pointer automatically owns the object it points to.
  • Using shared_ptr everywhere instead of designing ownership.

Practice

  1. Replace a simple new/delete example with make_unique.
  2. Explain why unique_ptr cannot be copied but can be moved.
  3. Draw a shared ownership count for two shared_ptr variables.
  4. Explain how weak_ptr can break a parent-child ownership cycle.

Practice solutions

Show worked solutions
  1. #include <memory>
    int main() {
        auto value = std::make_unique<int>(42);
    }
    make_unique requires C++14 or later and the smart pointer releases the object automatically.
  2. Copying a unique_ptr would create two exclusive owners. Moving transfers ownership to the destination and leaves the source empty.
  3. After auto first = std::make_shared<int>(7);, the strong owner count is one. After auto second = first;, it is two. When one owner is destroyed, it decreases by one.
  4. Store the back-reference as std::weak_ptr<Parent> instead of std::shared_ptr<Parent>. A weak_ptr does not increase the strong ownership count; call lock() to obtain a temporary shared_ptr if the object still exists.

Check your understanding

Which smart pointer should you choose when there is one clear owner?

Answer: Usually std::unique_ptr, because it expresses exclusive ownership and cleans up automatically.

Summary

Prefer RAII and standard-library resource managers. Use smart pointers to express ownership clearly: unique for one owner, shared for multiple owners, and weak for non-owning observation of shared objects.

References