AOSP Expert & Production Engineering
3 min read

Smart Pointers & RAII

std::unique_ptr: Exclusive Ownership

In modern C++, manual memory management using raw new and delete is strongly discouraged. std::unique_ptr is the cornerstone of safe memory management. It enforces exclusive ownership semantics: a dynamically allocated object is owned by exactly one std::unique_ptr at a time.

When the unique_ptr goes out of scope, the underlying object is automatically destroyed. In AOSP, this is the default smart pointer choice.

#include <memory>

class HardwareModule {
public:
    void initialize() {}
};

void load_module() {
    // Prefer std::make_unique over raw new
    std::unique_ptr<HardwareModule> module = std::make_unique<HardwareModule>();
    module->initialize();
    
    // Memory is safely reclaimed here when 'module' goes out of scope.
}

Ownership can be transferred using std::move:

std::unique_ptr<HardwareModule> transfer_module() {
    auto mod = std::make_unique<HardwareModule>();
    return mod; // Automatically moved due to copy elision / RVO
}

std::shared_ptr: Shared Ownership with Ref Count

std::shared_ptr provides shared ownership. Multiple shared_ptr instances can point to the same object. The system maintains a reference count; the underlying object is destroyed only when the last shared_ptr pointing to it is destroyed.

While useful, std::shared_ptr introduces performance overhead because the reference counter must be modified atomically to guarantee thread safety. It should only be used when an object's lifespan is genuinely non-deterministic and shared across multiple independent architectural components.

#include <memory>

void shared_example() {
    std::shared_ptr<int> data = std::make_shared<int>(42);
    std::shared_ptr<int> copy = data; // Ref count increments to 2
} // Ref count drops to 0, memory freed

std::weak_ptr: Break Cycles

A major flaw with std::shared_ptr is the potential for cyclic references (A holds a shared_ptr to B, and B holds a shared_ptr to A). The reference count will never reach zero, causing a memory leak.

std::weak_ptr observes a shared_ptr but does not increase the reference count. Before using the object, a weak_ptr must be temporarily converted to a shared_ptr using the lock() method to ensure the object hasn't been destroyed.

std::shared_ptr<int> owner = std::make_shared<int>(100);
std::weak_ptr<int> observer = owner;

if (std::shared_ptr<int> temp = observer.lock()) {
    // Object is still alive, safe to use 'temp'
}

Android sp and wp

Before C++11 introduced standard smart pointers, Android developed its own equivalents: sp<> (Strong Pointer) and wp<> (Weak Pointer), defined in utils/StrongPointer.h.

These heavily populate older AOSP code and are deeply integrated into the Binder IPC framework. An object must inherit from Android's RefBase class to be manageable by sp<> and wp<>.

While new code should prefer std::unique_ptr and std::shared_ptr, interacting with Binder services requires using sp<IBinder>.

RAII Pattern for Resource Management

Resource Acquisition Is Initialization (RAII) is a core C++ paradigm. The fundamental idea is that resources (memory, file descriptors, mutex locks) are acquired during object construction and automatically released during object destruction.

Smart pointers are a form of RAII for memory. Android relies on RAII to prevent resource leaks during complex control flows.

#include <mutex>

std::mutex system_lock;

void critical_section() {
    // std::lock_guard is an RAII wrapper for mutexes
    std::lock_guard<std::mutex> lock(system_lock);
    
    // Do work...
    // If an exception was enabled or an early return occurs,
    // the mutex is guaranteed to be unlocked as 'lock' goes out of scope.
}

Android RefBase Class

android::RefBase is the base class that provides intrinsic reference counting for sp<> and wp<>. When you create a class that needs to be passed across Binder boundaries, it typically inherits from RefBase.

RefBase manages two counters: a strong reference count and a weak reference count. It allows objects to trigger specific lifecycle callbacks, such as onFirstRef() and onLastStrongRef(), allowing services to initialize or tear down internal states cleanly when clients connect or disconnect.

Previous Lesson
STL in AOSP
Course Complete!
You've finished all lessons.