Implement std::unique_ptr

/*
Implementing your own version of std::unique_ptr in C++ involves creating a
class that takes ownership of a dynamically allocated resource and ensures
that the resource is properly deallocated when the unique_ptr goes out of
scope.

This MyUniquePtr class mimics the behavior of std::unique_ptr. 
It has move semantics, disallows copy operations, and ensures that the
owned resource is properly deallocated when the MyUniquePtr goes out
of scope.
*/

#include <iostream>

template <typename T>
class MyUniquePtr {
private:
    T* ptr;

public:
    // Constructor
    explicit MyUniquePtr(T* p = nullptr) : ptr(p) {}

    // Destructor
    ~MyUniquePtr() {
        delete ptr;
    }

    // Disable copy constructor and copy assignment
    MyUniquePtr(const MyUniquePtr&) = delete;
    MyUniquePtr& operator=(const MyUniquePtr&) = delete;

    // Move constructor
    MyUniquePtr(MyUniquePtr&& other) noexcept : ptr(other.ptr) {
        other.ptr = nullptr;
    }

    // Move assignment
    MyUniquePtr& operator=(MyUniquePtr&& other) noexcept {
        if (this != &other) {
            delete ptr;
            ptr = other.ptr;
            other.ptr = nullptr;
        }
        return *this;
    }

    // Dereference operator
    T& operator*() const {
        return *ptr;
    }

    // Member access operator
    T* operator->() const {
        return ptr;
    }

    // Release ownership
    T* release() {
        T* releasedPtr = ptr;
        ptr = nullptr;
        return releasedPtr;
    }

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

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

    // Boolean conversion for conditional checks
    explicit operator bool() const {
        return ptr != nullptr;
    }
};

// Example usage
int main() {
    MyUniquePtr<int> myUniquePtr(new int(42));

    if (myUniquePtr) {
        std::cout << "Value: " << *myUniquePtr << std::endl;
    }

    MyUniquePtr<int> anotherUniquePtr = std::move(myUniquePtr);

    if (!myUniquePtr) {
        std::cout << "myUniquePtr is now null" << std::endl;
    }

    return 0;
}