Sobes.tech
Middle+

How to write a smart pointer for one or multiple objects?

sobes.tech AI

Answer from AI

#include <atomic>
#include <utility>

// Simple smart pointer for a single object (similar to std::unique_ptr)
template <typename T>
class UniquePointer {
public:
    // Constructor accepting a raw pointer
    explicit UniquePointer(T* ptr = nullptr) : ptr_(ptr) {}

    // Destructor
    ~UniquePointer() {
        delete ptr_;
    }

    // Disable copying and assignment
    UniquePointer(const UniquePointer&) = delete;
    UniquePointer& operator=(const UniquePointer&) = delete;

    // Allow moving
    UniquePointer(UniquePointer&& other) noexcept : ptr_(other.ptr_) {
        other.ptr_ = nullptr;
    }

    UniquePointer& operator=(UniquePointer&& other) noexcept {
        if (this != &other) {
            delete ptr_;
            ptr_ = other.ptr_;
            other.ptr_ = nullptr;
        }
        return *this;
    }

    // Access to the object
    T* operator->() const { return ptr_; }
    T& operator*() const { return *ptr_; }

    // Get raw pointer
    T* get() const { return ptr_; }

    // Detach pointer
    T* release() {
        T* temp = ptr_;
        ptr_ = nullptr;
        return temp;
    }

    // Reset pointer
    void reset(T* ptr = nullptr) {
        if (ptr_ != ptr) {
            delete ptr_;
            ptr_ = ptr;
        }
    }

    // Check for null
    operator bool() const { return ptr_ != nullptr; }

private:
    T* ptr_; // Raw pointer
};

// Simple smart pointer for one or multiple objects with reference counting (similar to std::shared_ptr)
template <typename T>
class SharedPointer {
private:
    T* ptr_;                    // Raw pointer to object(s)
    std::atomic<int>* ref_count_; // Pointer to reference count (atomic for thread safety)

public:
    // Default constructor
    SharedPointer() : ptr_(nullptr), ref_count_(nullptr) {}

    // Constructor accepting a raw pointer
    explicit SharedPointer(T* ptr) : ptr_(ptr), ref_count_(new std::atomic<int>(1)) {}

    // Copy constructor
    SharedPointer(const SharedPointer& other) : ptr_(other.ptr_), ref_count_(other.ref_count_) {
        if (ref_count_) {
            (*ref_count_)++; // Increment reference count
        }
    }

    // Copy assignment operator
    SharedPointer& operator=(const SharedPointer& other) {
        if (this != &other) {
            // Decrement current reference count
            decrement_ref();

            ptr_ = other.ptr_;
            ref_count_ = other.ref_count_;

            // Increment new reference count
            if (ref_count_) {
                (*ref_count_)++;
            }
        }
        return *this;
    }

    // Move constructor
    SharedPointer(SharedPointer&& other) noexcept : ptr_(other.ptr_), ref_count_(other.ref_count_) {
        other.ptr_ = nullptr;
        other.ref_count_ = nullptr;
    }

    // Move assignment operator
    SharedPointer& operator=(SharedPointer&& other) noexcept {
        if (this != &other) {
            // Decrement current reference count
            decrement_ref();

            ptr_ = other.ptr_;
            ref_count_ = other.ref_count_;

            other.ptr_ = nullptr;
            other.ref_count_ = nullptr;
        }
        return *this;
    }

    // Destructor
    ~SharedPointer() {
        decrement_ref();
    }

    // Access to the object
    T* operator->() const { return ptr_; }
    T& operator*() const { return *ptr_; }

    // Get raw pointer
    T* get() const { return ptr_; }

    // Get reference count
    long use_count() const {
        if (ref_count_) {
            return ref_count_->load();
        }
        return 0;
    }

    // Check for null
    operator bool() const { return ptr_ != nullptr; }

private:
    // Helper to decrement reference count and delete if zero
    void decrement_ref() {
        if (ref_count_) {
            if (--(*ref_count_) == 0) {
                delete ptr_;      // Delete object(s)
                delete ref_count_; // Delete counter
                ptr_ = nullptr;
                ref_count_ = nullptr;
            }
        }
    }
};

// Specialization for array (for SharedPointer)
template <typename T>
class SharedPointer<T[]> {
private:
    T* ptr_;                    // Raw pointer to array
    std::atomic<int>* ref_count_; // Pointer to reference count (atomic)

public:
    // Constructor accepting raw pointer to array
    explicit SharedPointer(T* ptr) : ptr_(ptr), ref_count_(new std::atomic<int>(1)) {}

    // Copy constructor
    SharedPointer(const SharedPointer& other) : ptr_(other.ptr_), ref_count_(other.ref_count_) {
        if (ref_count_) {
            (*ref_count_)++;
        }
    }

    // Other constructors and operators similar to SharedPointer for single object,
    // but destructor should use `delete[]`.

    // Destructor for array
    ~SharedPointer() {
        if (ref_count_) {
            if (--(*ref_count_) == 0) {
                delete[] ptr_;    // Delete array
                delete ref_count_;
                ptr_ = nullptr;
                ref_count_ = nullptr;
            }
        }
    }

    // Access array elements
    T& operator[](size_t index) const { return ptr_[index]; }

    // Get raw pointer
    T* get() const { return ptr_; }

    // Get reference count
    long use_count() const {
        if (ref_count_) {
            return ref_count_->load();
        }
        return 0;
    }

    // Check for null
    operator bool() const { return ptr_ != nullptr; }
};