Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <memory>
- #include <cstddef>
- #include <iostream>
- #include <string>
- #include <type_traits>
- #include <utility>
- #include <cassert>
- #include <type_traits>
- class MyInt {
- public:
- static int AliveCount() {
- return count_alive;
- }
- MyInt() {
- ++count_alive;
- }
- MyInt(int value) : value_(value) {
- ++count_alive;
- };
- MyInt(const MyInt& other) : value_(other.value_) {
- ++count_alive;
- }
- MyInt(MyInt&&) = delete;
- MyInt& operator=(const MyInt& other) {
- value_ = other.value_;
- ++count_alive;
- return *this;
- }
- MyInt& operator=(MyInt&& other) = delete;
- ~MyInt() {
- --count_alive;
- }
- bool operator==(int other) const {
- return value_ == other;
- }
- private:
- int value_;
- inline static int count_alive = 0;
- };
- template <class T>
- class Deleter {
- public:
- Deleter() = default;
- Deleter(int tag) : tag_(tag) {
- }
- Deleter(const Deleter&) = delete;
- Deleter(Deleter&& rhs) noexcept : tag_(rhs.tag_) {
- rhs.tag_ = 0;
- }
- Deleter& operator=(const Deleter&) = delete;
- Deleter& operator=(Deleter&& r) noexcept {
- tag_ = r.tag_;
- r.tag_ = 0;
- return *this;
- }
- ~Deleter() = default;
- int GetTag() const {
- return tag_;
- }
- void operator()(T* p) const {
- static_assert(sizeof(T) > 0);
- static_assert(!std::is_void<T>::value);
- delete p;
- }
- bool IsConst() const {
- return true;
- }
- bool IsConst() {
- return false;
- }
- private:
- int tag_ = 0;
- };
- template <class T>
- class Deleter<T[]> {
- public:
- Deleter() = default;
- Deleter(int tag) : tag_(tag) {
- }
- Deleter(const Deleter&) = delete;
- Deleter(Deleter&& rhs) noexcept : tag_(rhs.tag_) {
- rhs.tag_ = 0;
- }
- Deleter& operator=(const Deleter&) = delete;
- Deleter& operator=(Deleter&& r) noexcept {
- tag_ = r.tag_;
- r.tag_ = 0;
- return *this;
- }
- ~Deleter() = default;
- int GetTag() const {
- return tag_;
- }
- void operator()(T* p) const {
- static_assert(sizeof(T) > 0);
- static_assert(!std::is_void<T>::value);
- delete[] p;
- }
- bool IsConst() const {
- return true;
- }
- bool IsConst() {
- return false;
- }
- private:
- int tag_ = 0;
- };
- template <typename T>
- class CopyableDeleter {
- public:
- CopyableDeleter() = default;
- CopyableDeleter(int tag) : tag_(tag) {
- }
- CopyableDeleter(const CopyableDeleter&) = default;
- CopyableDeleter(CopyableDeleter&& rhs) noexcept : tag_(rhs.tag_) {
- rhs.tag_ = 0;
- }
- CopyableDeleter& operator=(const CopyableDeleter&) = default;
- CopyableDeleter& operator=(CopyableDeleter&& r) noexcept {
- tag_ = r.tag_;
- r.tag_ = 0;
- return *this;
- }
- ~CopyableDeleter() = default;
- int GetTag() const {
- return tag_;
- }
- void operator()(T* p) const {
- static_assert(sizeof(T) > 0);
- static_assert(!std::is_void<T>::value);
- delete p;
- }
- bool IsConst() const {
- return true;
- }
- bool IsConst() {
- return false;
- }
- private:
- int tag_ = 0;
- };
- struct VoidPtrDeleter {
- void operator()(void* ptr) {
- free(ptr);
- }
- };
- template <typename T>
- void DeleteFunction(T* ptr) {
- delete ptr;
- }
- template <typename T>
- struct StatefulDeleter {
- int some_useless_field = 0;
- void operator()(T* ptr) {
- delete ptr;
- ++some_useless_field;
- }
- };
- template <typename T, std::size_t I, bool = std::is_empty_v<T> && !std::is_final_v<T>>
- struct CompressedPairElement {
- public:
- CompressedPairElement() {
- }
- template <typename Tp>
- CompressedPairElement(Tp&& other) : value_(std::forward<decltype(other)>(other)) {
- }
- template <typename Tp>
- CompressedPairElement& operator=(Tp&& other) {
- value_ = std::forward<decltype(other)>(other);
- }
- const T& Get() const {
- return value_;
- }
- T& Get() {
- return value_;
- }
- private:
- T value_{};
- };
- template <typename T, std::size_t I>
- struct CompressedPairElement<T, I, true> : public T {
- public:
- CompressedPairElement() {
- }
- template <typename Tp>
- CompressedPairElement(Tp&& other) {
- }
- const T& Get() const {
- return *this;
- }
- T& Get() {
- return *this;
- }
- };
- template <typename F, typename S>
- class CompressedPair : protected CompressedPairElement<F, 0>,
- protected CompressedPairElement<S, 1> {
- using First = CompressedPairElement<F, 0>;
- using Second = CompressedPairElement<S, 1>;
- public:
- CompressedPair() {
- }
- template <typename U, typename V>
- CompressedPair(U&& first, V&& second)
- : First(std::forward<decltype(first)>(first)),
- Second(std::forward<decltype(second)>(second)) {
- }
- F& GetFirst() {
- return First::Get();
- }
- S& GetSecond() {
- return Second::Get();
- }
- const F& GetFirst() const {
- return First::Get();
- }
- const S& GetSecond() const {
- return Second::Get();
- }
- };
- int counter = 0;
- // Primary template
- template <typename T, typename Deleter = std::default_delete<T>>
- class UniquePtr {
- public:
- // Constructors
- explicit UniquePtr(T* ptr = nullptr) {
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " constructor from pointer" << std::endl;
- uptr_ = CompressedPair<T*, Deleter>(ptr, Deleter());
- }
- template<typename Del>
- UniquePtr(T *ptr, Del&& deleter) : uptr_(CompressedPair<T*, Deleter>(ptr, std::forward<decltype(deleter)>(deleter))){
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " constructor from pointer with deleter" << std::endl;
- }
- UniquePtr(const UniquePtr& other) = delete;
- UniquePtr(UniquePtr&& other) noexcept {
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " move constructor from " << other.id << std::endl;
- if (uptr_.GetFirst() != other.uptr_.GetFirst()) {
- std::swap(uptr_, other.uptr_);
- other.uptr_.GetFirst() = nullptr;
- }
- }
- template <typename Tp>
- UniquePtr(UniquePtr<Tp>&& other) noexcept : uptr_(other.uptr_.GetFirst(), std::forward<decltype(other.uptr_.GetSecond())>(other.uptr_.GetSecond())) {
- ++counter;
- id = std::to_string(counter);
- other.uptr_.GetFirst() = nullptr;
- std::cerr << id << " derived move constructor from " << other.id << std::endl;
- }
- // `operator=`-s
- UniquePtr& operator=(const UniquePtr& other) = delete;
- UniquePtr& operator=(UniquePtr&& other) noexcept {
- std::cerr << id << " = " << other.id << std::endl;
- if (uptr_.GetFirst() != other.uptr_.GetFirst()) {
- std::swap(uptr_.GetFirst(), other.uptr_.GetFirst());
- uptr_.GetSecond() = std::forward<Deleter>(other.uptr_.GetSecond());
- other.uptr_.GetSecond()(other.uptr_.GetFirst());
- other.uptr_.GetFirst() = nullptr;
- }
- return *this;
- }
- UniquePtr& operator=(std::nullptr_t) {
- std::cerr << id << " = nullptr" << std::endl;
- uptr_.GetSecond()(uptr_.GetFirst());
- uptr_ = CompressedPair<T*, Deleter>(nullptr, Deleter());
- return *this;
- }
- // Destructor
- ~UniquePtr() {
- std::cerr << id << " deleted" << std::endl;
- uptr_.GetSecond()(uptr_.GetFirst());
- }
- //Modifiers
- T* Release() noexcept {
- std::cerr << "released " << id << std::endl;
- T* tmp = uptr_.GetFirst();
- uptr_.GetFirst() = nullptr;
- return tmp;
- }
- void Reset(T* ptr = nullptr) noexcept {
- std::cerr << "reset " << id << std::endl;
- T* old_ptr = uptr_.GetFirst();
- uptr_.GetFirst() = ptr;
- if (old_ptr) {
- uptr_.GetSecond()(old_ptr);
- }
- }
- void Swap(UniquePtr& other) noexcept {
- std::cerr << id << " swapped with " << other.id << std::endl;
- std::swap(uptr_, other.uptr_);
- }
- //Observers
- T* Get() const noexcept {
- std::cerr << "got " << id << std::endl;
- return uptr_.GetFirst();
- }
- Deleter& GetDeleter() {
- std::cerr << "got deleter " << id << std::endl;
- return uptr_.GetSecond();
- }
- const Deleter& GetDeleter() const {
- std::cerr << "got deleter const " << id << std::endl;
- return uptr_.GetSecond();
- }
- explicit operator bool() const {
- std::cerr << "checked if nullptr " << id << std::endl;
- return uptr_.GetFirst() != nullptr;
- }
- // Single-object dereference operators
- typename std::add_lvalue_reference<T>::type
- operator*() const {
- std::cerr << "operator* for " << id << std::endl;
- return *Get();
- }
- T* operator->() const {
- std::cerr << "operator -> from " << id << std::endl;
- return uptr_.GetFirst();
- }
- private:
- CompressedPair<T*, Deleter> uptr_;
- template<class U, class D>
- friend class UniquePtr;
- std::string id = "NULLPOINTER";
- };
- // Specialization for arrays
- template <typename T, typename Deleter>
- class UniquePtr<T[], Deleter> {
- public:
- //Constructors
- explicit UniquePtr(T* ptr = nullptr) {
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " constructor from pointer" << std::endl;
- uptr_ = CompressedPair<T*, Deleter>(ptr, Deleter());
- }
- UniquePtr(T *ptr, Deleter deleter) {
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " constructor from pointer with deleter" << std::endl;;
- uptr_ = CompressedPair<T*, Deleter>(ptr, deleter);
- }
- UniquePtr(const UniquePtr& other) = delete;
- UniquePtr(UniquePtr&& other) noexcept {
- ++counter;
- id = std::to_string(counter);
- std::cerr << id << " move constructor from " << other.id << std::endl;
- if (uptr_.GetFirst() != other.uptr_.GetFirst()) {
- uptr_ = other.uptr_;
- other.uptr_.GetFirst() = nullptr;
- }
- }
- template <typename Tp>
- UniquePtr(UniquePtr<Tp>&& other) noexcept : uptr_(other.uptr_.GetFirst(), other.uptr_.GetSecond()) {
- ++counter;
- id = std::to_string(counter);
- other.uptr_.GetFirst() = nullptr;
- std::cerr << id << " derived move constructor from " << other.id << std::endl;
- }
- // `operator=`-s
- UniquePtr& operator=(const UniquePtr& other) = delete;
- UniquePtr& operator=(UniquePtr&& other) noexcept {
- std::cerr << id << " = " << other.id << std::endl;
- if (uptr_.GetFirst() != other.uptr_.GetFirst()) {
- std::swap(uptr_, other.uptr_);
- other.uptr_.GetFirst() = nullptr;
- }
- return *this;
- }
- UniquePtr& operator=(std::nullptr_t) {
- std::cerr << id << " = nullptr" << std::endl;
- uptr_.GetSecond()(uptr_.GetFirst());
- uptr_ = CompressedPair<T*, Deleter>(nullptr, Deleter());
- return *this;
- }
- // Destructor
- ~UniquePtr() {
- std::cerr << id << " deleted" << std::endl;
- uptr_.GetSecond()(uptr_.GetFirst());
- }
- // Modifiers
- T* Release() noexcept {
- std::cerr << "released " << id << std::endl;
- T* tmp = uptr_.GetFirst();
- uptr_.GetFirst() = nullptr;
- return tmp;
- }
- void Reset(T* ptr = nullptr) noexcept {
- std::cerr << "reset " << id << std::endl;
- T* old_ptr = uptr_.GetFirst();
- uptr_.GetFirst() = ptr;
- if (old_ptr) {
- uptr_.GetSecond()(old_ptr);
- }
- }
- void Swap(UniquePtr& other) noexcept {
- std::swap(uptr_, other.uptr_);
- }
- T& operator[](size_t i) {
- return Get()[i];
- }
- //Observers
- T* Get() const noexcept {
- std::cerr << "got " << id << std::endl;
- return uptr_.GetFirst();
- }
- Deleter& GetDeleter() {
- return uptr_.GetSecond();
- }
- const Deleter& GetDeleter() const {
- return uptr_.GetSecond();
- }
- explicit operator bool() const {
- return uptr_.GetFirst() != nullptr;
- }
- const T& operator[](size_t i) const {
- return Get()[i];
- }
- private:
- CompressedPair<T*, Deleter> uptr_;
- template<class U, class D>
- friend class UniquePtr;
- std::string id = "NULLPOINTER";
- };
- #include <tuple>
- int main() {
- {
- const CopyableDeleter<MyInt> cd;
- UniquePtr<MyInt, CopyableDeleter<MyInt>> s(new MyInt, cd);
- }
- {
- Deleter<MyInt> d;
- UniquePtr<MyInt, Deleter<MyInt>> s(new MyInt, std::move(d));
- }
- {
- UniquePtr<MyInt, Deleter<MyInt>> s(new MyInt, Deleter<MyInt>{});
- }
- {
- Deleter<MyInt> d;
- UniquePtr<MyInt, Deleter<MyInt>&> s(new MyInt, d);
- }
- {
- Deleter<MyInt> d;
- UniquePtr<MyInt, const Deleter<MyInt>&> s1(new MyInt, d);
- const Deleter<MyInt>& cr = d;
- UniquePtr<MyInt, const Deleter<MyInt>&> s2(new MyInt, cr);
- }
- std::cerr << std::endl;
- {
- MyInt* p1 = new MyInt(1);
- UniquePtr<MyInt, Deleter<MyInt>> s1(p1, Deleter<MyInt>(1));
- MyInt* p2 = new MyInt(2);
- UniquePtr<MyInt, Deleter<MyInt>> s2(p2, Deleter<MyInt>(2));
- s1.Swap(s2);
- assert(s1.Get() == p2);
- assert(*s1 == 2);
- assert(s2.Get() == p1);
- assert(*s2 == 1);
- assert(s1.GetDeleter().GetTag() == 2);
- assert(s2.GetDeleter().GetTag() == 1);
- assert(MyInt::AliveCount() == 2);
- std::swap(s1, s2);
- assert(s1.Get() == p1);
- assert(*s1 == 1);
- assert(s2.Get() == p2);
- assert(*s2 == 2);
- assert(s1.GetDeleter().GetTag() == 1);
- assert(s2.GetDeleter().GetTag() == 2);
- }
- {
- UniquePtr<MyInt, Deleter<MyInt>> s1(new MyInt, Deleter<MyInt>(5));
- MyInt* p = s1.Get();
- UniquePtr<MyInt, Deleter<MyInt>> s2(new MyInt);
- assert(MyInt::AliveCount() == 2);
- assert(s1.GetDeleter().GetTag() == 5);
- assert(s2.GetDeleter().GetTag() == 0);
- s2 = std::move(s1);
- assert(s2.Get() == p);
- assert(s1.Get() == nullptr);
- assert(MyInt::AliveCount() == 1);
- assert(s2.GetDeleter().GetTag() == 5);
- assert(s1.GetDeleter().GetTag() == 0);
- }
- {
- CopyableDeleter<MyInt> d1(5);
- UniquePtr<MyInt, CopyableDeleter<MyInt>&> s1(new MyInt, d1);
- MyInt* p1 = s1.Get();
- CopyableDeleter<MyInt> d2(6);
- UniquePtr<MyInt, CopyableDeleter<MyInt>&> s2(new MyInt, d2);
- assert(MyInt::AliveCount() == 2);
- s2 = std::move(s1);
- assert(s2.Get() == p1);
- assert(s1.Get() == nullptr);
- assert(MyInt::AliveCount() == 1);
- assert(d1.GetTag() == 5);
- assert(d2.GetTag() == 5);
- }
- {
- UniquePtr<MyInt, Deleter<MyInt>> p;
- assert(!p.GetDeleter().IsConst());
- }
- {
- const UniquePtr<MyInt, Deleter<MyInt>> p;
- assert(p.GetDeleter().IsConst());
- }
- {
- using UDRef = UniquePtr<MyInt, Deleter<MyInt>&>;
- Deleter<MyInt> d;
- UDRef p(nullptr, d);
- const UDRef& cp = p;
- assert(!p.GetDeleter().IsConst());
- assert(!cp.GetDeleter().IsConst());
- }
- {
- using UDConstRef = UniquePtr<MyInt, const Deleter<MyInt>&>;
- const Deleter<MyInt> d;
- UDConstRef p(nullptr, d);
- const UDConstRef& cp = p;
- assert(p.GetDeleter().IsConst());
- assert(cp.GetDeleter().IsConst());
- }
- {
- UniquePtr<void, VoidPtrDeleter> p(malloc(100));
- }
- {
- UniquePtr<MyInt[]> u(new MyInt[100]);
- assert(MyInt::AliveCount() == 100);
- u.Reset();
- assert(MyInt::AliveCount() == 0);
- }
- {
- UniquePtr<MyInt[], Deleter<MyInt[]>> u(new MyInt[100]);
- assert(MyInt::AliveCount() == 100);
- u.Reset();
- assert(MyInt::AliveCount() == 0);
- }
- int* arr = new int[5];
- for (size_t i = 0; i < 5; ++i) {
- arr[i] = i;
- }
- UniquePtr<int[]> u(arr);
- for (int i = 0; i < 5; ++i) {
- assert(u[i] == i);
- u[i] = -i;
- assert(u[i] == -i);
- }
- {
- std::cerr << sizeof(UniquePtr<int>) << " " << sizeof(void*) << "\n";
- // static_assert(sizeof(UniquePtr<int>) == sizeof(void*));
- // static_assert(sizeof(UniquePtr<int, std::default_delete<int>>) == sizeof(int*));
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement