CodeNebula
C++11coreintermediate

std::shared_ptr (C++11 Addition)

C++11 · Modern Revolution · Compiler flag: -std=c++11

Explanation

Smart pointer with shared ownership, tracking reference counts.

Real-World Scenario

Share a resource across multiple game objects.

Quick Snippet

snippet.cpp
#include <memory> std::shared_ptr<int> ptr = std::make_shared<int>(5);

Full Example

shared_ptr.cpp
// CodeNebula - C++11 Example: std::shared_ptr
// Compile: g++ -std=c++11 -Wall -Wextra -o example shared_ptr.cpp
//
// This example demonstrates:
// - std::shared_ptr for shared ownership of heap objects
// - Reference counting and automatic deletion
// - std::make_shared for efficient allocation
// - Custom deleters
// - use_count() to observe reference counts

#include <iostream>
#include <memory>
#include <string>
#include <vector>

// ============================================================
// 1. A class to track construction/destruction
// ============================================================
class Resource {
    std::string name_;
public:
    Resource(const std::string& name) : name_(name) {
        std::cout << "  Resource \"" << name_ << "\" created" << std::endl;
    }

    ~Resource() {
        std::cout << "  Resource \"" << name_ << "\" destroyed" << std::endl;
    }

    void use() const {
        std::cout << "  Using resource: " << name_ << std::endl;
    }

    const std::string& name() const { return name_; }
};

// ============================================================
// 2. Function that shares ownership
// ============================================================
void holdReference(std::shared_ptr<Resource> ptr) {
    std::cout << "  holdReference: use_count = " << ptr.use_count() << std::endl;
    ptr->use();
}

// ============================================================
// 3. Factory that returns shared_ptr
// ============================================================
std::shared_ptr<Resource> createResource(const std::string& name) {
    return std::make_shared<Resource>(name);
}

int main() {
    std::cout << "=== std::shared_ptr ===" << std::endl;

    // Basic creation and usage
    std::cout << "\n--- Basic usage ---" << std::endl;
    {
        std::shared_ptr<Resource> p1 = std::make_shared<Resource>("Alpha");
        std::cout << "  use_count: " << p1.use_count() << std::endl;

        {
            std::shared_ptr<Resource> p2 = p1;  // Shared ownership
            std::cout << "  After copy, use_count: " << p1.use_count() << std::endl;
            p2->use();
        }
        std::cout << "  After p2 scope, use_count: " << p1.use_count() << std::endl;
    }
    std::cout << "  After all scopes: resource destroyed" << std::endl;

    // make_shared vs constructor
    std::cout << "\n--- make_shared vs new ---" << std::endl;
    auto sp1 = std::make_shared<Resource>("Efficient");  // Single allocation
    std::shared_ptr<Resource> sp2(new Resource("Two-alloc"));  // Two allocations
    sp1.reset();
    sp2.reset();

    // Sharing across function calls
    std::cout << "\n--- Shared across functions ---" << std::endl;
    {
        auto res = createResource("Shared");
        std::cout << "  Before call: use_count = " << res.use_count() << std::endl;
        holdReference(res);
        std::cout << "  After call: use_count = " << res.use_count() << std::endl;
    }

    // Container of shared_ptrs
    std::cout << "\n--- Container of shared_ptr ---" << std::endl;
    {
        std::vector<std::shared_ptr<Resource>> resources;
        auto r1 = std::make_shared<Resource>("DB");
        auto r2 = std::make_shared<Resource>("Cache");

        resources.push_back(r1);
        resources.push_back(r2);
        resources.push_back(r1);  // r1 shared again

        std::cout << "  r1 use_count: " << r1.use_count() << std::endl;
        std::cout << "  r2 use_count: " << r2.use_count() << std::endl;

        resources.clear();
        std::cout << "  After clear, r1 use_count: " << r1.use_count() << std::endl;
    }

    // Custom deleter
    std::cout << "\n--- Custom deleter ---" << std::endl;
    {
        auto deleter = [](Resource* p) {
            std::cout << "  Custom deleter for: " << p->name() << std::endl;
            delete p;
        };
        std::shared_ptr<Resource> custom(new Resource("Custom"), deleter);
        custom->use();
    }

    // Checking for null
    std::cout << "\n--- Null and boolean checks ---" << std::endl;
    std::shared_ptr<int> empty;
    std::shared_ptr<int> valid = std::make_shared<int>(42);
    std::cout << "  empty is null: " << (empty ? "no" : "yes") << std::endl;
    std::cout << "  valid is null: " << (valid ? "no" : "yes") << std::endl;
    std::cout << "  *valid = " << *valid << std::endl;

    return 0;
}

// Expected output:
// === std::shared_ptr ===
//
// --- Basic usage ---
//   Resource "Alpha" created
//   use_count: 1
//   After copy, use_count: 2
//   Using resource: Alpha
//   After p2 scope, use_count: 1
//   Resource "Alpha" destroyed
//   After all scopes: resource destroyed
//
// --- make_shared vs new ---
//   Resource "Efficient" created
//   Resource "Two-alloc" created
//   Resource "Efficient" destroyed
//   Resource "Two-alloc" destroyed
//
// --- Shared across functions ---
//   Resource "Shared" created
//   Before call: use_count = 1
//   holdReference: use_count = 2
//   Using resource: Shared
//   After call: use_count = 1
//   Resource "Shared" destroyed
//
// --- Container of shared_ptr ---
//   Resource "DB" created
//   Resource "Cache" created
//   r1 use_count: 3
//   r2 use_count: 2
//   After clear, r1 use_count: 1
//   Resource "Cache" destroyed
//   Resource "DB" destroyed
//
// --- Custom deleter ---
//   Resource "Custom" created
//   Using resource: Custom
//   Custom deleter for: Custom
//   Resource "Custom" destroyed
//
// --- Null and boolean checks ---
//   empty is null: yes
//   valid is null: no
//   *valid = 42
Run command
g++ -std=c++11 -Wall -Wextra -o example shared_ptr.cpp