#include <iostream>

template<typename T>
class SharedPtr {
    T* value;
    int* ref_count;

public:
    SharedPtr(T* value) : value(value) {
        ref_count = new int;
        *ref_count = 1;
    }

    SharedPtr(const SharedPtr& other) {
        value = other.value;
        ref_count = other.ref_count;
        (*ref_count)++;
    }

    SharedPtr(SharedPtr&& other) {
        value = other.value;
        ref_count = other.ref_count;
        other.ref_count = nullptr;
    }

    ~SharedPtr() {
        if (ref_count == nullptr) {
            return;
        }

        if (*ref_count == 1) {
            delete value;
            delete ref_count;
        } else {
            (*ref_count)--;
        }
    }

    T& operator *() const {
        return *value;
    }

    T* operator ->() const {
        return value;
    }
};

struct Pituh {
    Pituh() {
        std::cout << "Koko()" << std::endl;
    }
    ~Pituh() {
        std::cout << "~Koko()" << std::endl;
    }
    void kukareku() {
        std::cout << "kukareku" << std::endl;
    }
};

void kukareknut1(SharedPtr<Pituh> pet) {
    pet->kukareku();
}
void kukareknut2(SharedPtr<Pituh> pet) {
    (*pet).kukareku();
}

int main() {
    {
        SharedPtr<Pituh>(new Pituh);
    }
    std::cout << std::endl;

    {
        SharedPtr<Pituh> x(new Pituh);
        auto y = x;
        kukareknut1(y);
        kukareknut2(std::move(y));
    }
    std::cout << std::endl;
}