From 044e4aba93a64110975cdee53241c31d8caacff5 Mon Sep 17 00:00:00 2001 From: ChrisBenua Date: Fri, 19 Feb 2021 20:35:05 +0300 Subject: [PATCH 1/5] Implemented shared_ptr and weak_ptr --- .../homework/SharedPointer/CMakeLists.txt | 1 + .../SharedPointer/src/control/control.h | 114 ++++++- .../SharedPointer/src/shared_ptr/shared_ptr.h | 319 +++++++++++++++--- module-1/homework/SharedPointer/tests.cpp | 18 +- 4 files changed, 379 insertions(+), 73 deletions(-) diff --git a/module-1/homework/SharedPointer/CMakeLists.txt b/module-1/homework/SharedPointer/CMakeLists.txt index 624cb834..90bf5295 100644 --- a/module-1/homework/SharedPointer/CMakeLists.txt +++ b/module-1/homework/SharedPointer/CMakeLists.txt @@ -35,6 +35,7 @@ if (CMAKE_VERSION VERSION_LESS 2.8.11) endif() add_subdirectory(src/shared_ptr) +add_subdirectory(src/control) add_executable(runner tests.cpp) target_link_libraries(runner LINK_PUBLIC shared_ptr gtest_main) diff --git a/module-1/homework/SharedPointer/src/control/control.h b/module-1/homework/SharedPointer/src/control/control.h index 55c08056..34afb16c 100644 --- a/module-1/homework/SharedPointer/src/control/control.h +++ b/module-1/homework/SharedPointer/src/control/control.h @@ -1,26 +1,112 @@ #pragma once +#include + + class shared_count { - protected: - // Your code goes here... +protected: + std::atomic strong_count; + + virtual ~shared_count() {} +public: + explicit shared_count(size_t count = 0) noexcept: strong_count(count) {} + //delete copy + shared_count(const shared_count& c) = delete; + shared_count(shared_count&& c) = delete; + + void retain_shared() noexcept { + strong_count.fetch_add(1); + } + + bool release_shared() noexcept { + if (strong_count.fetch_sub(1) == 0) { + on_zero_shared(); + return true; + } + return false; + } + + long use_count() const noexcept { + return strong_count + 1; + } - public: - // Your code goes here... + virtual void on_zero_shared() noexcept = 0; }; class shared_weak_count : public shared_count { - private: - // Your code goes here... - - public: - // Your code goes here... +private: + std::atomic weak_count; + +protected: + virtual ~shared_weak_count() {} + +public: + //explicit shared_weak_count(size_t count = 1) noexcept: weak_count(count), shared_count(count) {} + shared_weak_count(size_t weak = 1, size_t strong = 0) noexcept: weak_count(weak), shared_count(strong) {} + + shared_weak_count(const shared_weak_count& c) = delete; + shared_weak_count(shared_weak_count&& c) = delete; + + + void retain_weak() noexcept { + weak_count.fetch_add(1); + } + + void retain_shared() noexcept { + shared_count::retain_shared(); + } + + void release_shared() noexcept { + if (shared_count::release_shared()) { + release_weak(); + } + } + + void release_weak() noexcept { + weak_count.fetch_sub(1); + } + + long use_count() const noexcept { + return shared_count::use_count(); + } + + virtual void on_zero_shared() noexcept = 0; + + virtual shared_weak_count* lock() = 0; +}; + +template +struct __default_deleter { + void operator()(T ptr) noexcept { + delete ptr; + } }; -template +template> class control_block : public shared_weak_count { - public: - // Your code goes here... +public: + control_block(T _t): ptr(_t), deleter(__default_deleter()) {} + + control_block(T _t, Deleter deleter): ptr(_t), deleter(deleter) {} + + control_block(const control_block& c) = delete; + + control_block(control_block&& c) = delete; + + void on_zero_shared() noexcept override { + deleter(ptr); + } + + shared_weak_count* lock() override { + if (use_count() > 0) { + control_block* res = new control_block(ptr, deleter); + res->retain_shared(); + return res; + } + return nullptr; + } - private: - // Your code goes here... +private: + T ptr; + Deleter deleter; }; diff --git a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h index 416d9890..7ebbd7fd 100644 --- a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h +++ b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h @@ -2,76 +2,193 @@ #include "../control/control.h" +template +struct remove_extent { using type = T; }; + +template +struct remove_extent { using type = T; }; + +template +struct remove_extent { using type = T; }; + // shared_ptr template class weak_ptr; template class shared_ptr { - public: - using element_type = T; - - constexpr shared_ptr() noexcept = default; - ~shared_ptr(); - - template - shared_ptr(Y* p); - - template - shared_ptr(Y* p, Deleter deleter) noexcept; - - shared_ptr(const shared_ptr& other) noexcept; - shared_ptr(shared_ptr&& other) noexcept; - - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - template - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - template - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - // Modifiers - void reset() noexcept; - - template - void reset(Y* p) noexcept; - - template - void reset(Y*p, Deleter deleter) noexcept; - - void swap(shared_ptr& other) noexcept; - - // Observers - T* get() const noexcept; - long use_count() const noexcept; - T& operator*() const noexcept; - T* operator->() const noexcept; - element_type& operator[](std::ptrdiff_t idx) const; - explicit operator bool() const noexcept; - - private: - // Your code goes here... +public: + using element_type = typename remove_extent::type; + + constexpr shared_ptr() noexcept = default; + ~shared_ptr(); + + template + explicit shared_ptr(Y* p); + + template + shared_ptr(Y* p, Deleter deleter) noexcept; + + shared_ptr(const shared_ptr& other) noexcept; + shared_ptr(shared_ptr&& other) noexcept; + + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + template + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + template + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + // Modifiers + void reset() noexcept; + + template + void reset(Y* p) noexcept; + + template + void reset(Y*p, Deleter deleter) noexcept; + + void swap(shared_ptr& other) noexcept; + + // Observers + T* get() const noexcept; + long use_count() const noexcept; + T& operator*() const noexcept; + T* operator->() const noexcept; + element_type& operator[](std::ptrdiff_t idx) const; + explicit operator bool() const noexcept; + + template + friend class weak_ptr; + +private: + + element_type* value_ptr = nullptr; + shared_weak_count* control_ptr = nullptr; }; -// make_shared +template +void shared_ptr::swap(shared_ptr &other) noexcept { + std::swap(control_ptr, other.control_ptr); + std::swap(value_ptr, other.value_ptr); +} -// Your code goes here... +template +template +shared_ptr::shared_ptr(Y* p): value_ptr(p), control_ptr(new control_block(p)) {} -// make_shared +template +shared_ptr::~shared_ptr() { + if (control_ptr) { + control_ptr->release_shared(); + } + value_ptr = nullptr; + control_ptr = nullptr; +} -// shared_ptr +template +template +shared_ptr::shared_ptr(Y* p, Deleter deleter) noexcept : + value_ptr(p), + control_ptr(new control_block(p, deleter)) + {} + +template +shared_ptr::shared_ptr(const shared_ptr& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(other.control_ptr) +{ + control_ptr->retain_shared(); +} + +template +shared_ptr::shared_ptr(shared_ptr&& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(other.control_ptr) +{ + other.control_ptr = nullptr; + other.value_ptr = nullptr; +} + +template +shared_ptr& shared_ptr::operator=(const shared_ptr& rhs) noexcept { + shared_ptr(rhs).swap(*this); + return *this; +} + +template +shared_ptr& shared_ptr::operator=(shared_ptr&& rhs) noexcept { + shared_ptr(std::forward(rhs)).swap(*this); + return *this; +} + +template +T* shared_ptr::get() const noexcept { + return value_ptr; +} + +template +long shared_ptr::use_count() const noexcept { + return control_ptr == nullptr ? 0 : control_ptr->use_count(); +} + +template +T& shared_ptr::operator*() const noexcept { + return *value_ptr; +} + +template +T* shared_ptr::operator->() const noexcept { + return value_ptr; +} + +template +shared_ptr::operator bool() const noexcept { + return use_count() > 0 && value_ptr != nullptr; +} + +template +typename shared_ptr::element_type& shared_ptr::operator[](std::ptrdiff_t idx) const { + return *(value_ptr + idx); +} + +template +void shared_ptr::reset() noexcept { + value_ptr = nullptr; + if (control_ptr) { + control_ptr->release_shared(); + } +} + +template +template +void shared_ptr::reset(Y* p) noexcept { + shared_ptr(p).swap(*this); +} + +template +template +void shared_ptr::reset(Y* p, Deleter deleter) noexcept { + shared_ptr(p, deleter).swap(*this); +} + +// make_shared +template +shared_ptr make_shared(Args&&... args) { + return shared_ptr(new T(std::forward(args)...)); +} -// Your code goes here... // shared_ptr +// weak_ptr template class weak_ptr { - using element_type = T; + using element_type = typename remove_extent::type ; public: @@ -99,12 +216,102 @@ class weak_ptr { template friend class shared_ptr; public: - // Your code goes here... + element_type* value_ptr = nullptr; + shared_weak_count* control_ptr = nullptr; }; -// weak_ptr +template +template +weak_ptr::weak_ptr(const shared_ptr& other): value_ptr(other.value_ptr), control_ptr(other.control_ptr) { + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr::weak_ptr(const weak_ptr& other) noexcept : + value_ptr(other.value_ptr), control_ptr(other.control_ptr) +{ + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr::weak_ptr(weak_ptr&& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(std::move(other.control_ptr)) + { + other.value_ptr = nullptr; + other.control_ptr = nullptr; + } + +template +void weak_ptr::reset() noexcept { + if (control_ptr && value_ptr) { + value_ptr = nullptr; + control_ptr->release_weak(); + control_ptr = nullptr; + } +} + +template +void weak_ptr::swap(weak_ptr& other) noexcept { + std::swap(value_ptr, other.value_ptr); + std::swap(control_ptr, other.control_ptr); +} + +template +bool weak_ptr::expired() noexcept { + return control_ptr == nullptr || control_ptr->use_count() <= 0; +} -// Your code goes here... +template +shared_ptr weak_ptr::lock() const noexcept { + shared_ptr res; + res.control_ptr = control_ptr ? control_ptr->lock() : control_ptr; + if (res.control_ptr) { + res.value_ptr = this->value_ptr; + } + + return res; +} + +template +template +weak_ptr& weak_ptr::operator=(const shared_ptr& other) { + reset(); + + this->control_ptr = other.control_ptr; + this->value_ptr = other.value_ptr; + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr& weak_ptr::operator=(const weak_ptr& other) noexcept { + if (this == other) { + return *this; + } + reset(); + this->value_ptr = other.value_ptr; + this->control_ptr = other.control_ptr; + if (control_ptr) { + control_ptr->retain_weak(); + } + + return *this; +} + +template +weak_ptr& weak_ptr::operator=(weak_ptr&& other) noexcept { + reset(); + this->value_ptr = other.value_ptr; + this->control_ptr = other.control_ptr; + other.control_ptr = nullptr; + other.value_ptr = nullptr; -// weak_ptr \ No newline at end of file + return *this; +} diff --git a/module-1/homework/SharedPointer/tests.cpp b/module-1/homework/SharedPointer/tests.cpp index f38a6f6a..b9f0738c 100644 --- a/module-1/homework/SharedPointer/tests.cpp +++ b/module-1/homework/SharedPointer/tests.cpp @@ -2,6 +2,7 @@ #include #include "src/shared_ptr/shared_ptr.h" +#include #include "gtest/gtest.h" @@ -63,6 +64,10 @@ TEST(SharedMoveAssignment, Test1) { contrainer* raw_s1 = s1.get(); shared_ptr s2; s2 = std::move(s1); + ASSERT_EQ(s1.use_count(), 0); + ASSERT_EQ(s1.get(), nullptr); + ASSERT_EQ(s2.get(), raw_s1); + ASSERT_EQ(s2.use_count(), 1); ASSERT_TRUE(s1.use_count() == 0 && s1.get() == nullptr && s2.get() == raw_s1 && s2.use_count() == 1); } @@ -77,6 +82,12 @@ TEST(SharedAssignment, Test1) { ASSERT_TRUE(s1.use_count() == 3 && s2.use_count() == 3 && s3.use_count() == 3 && s1.get() == s2.get() && s2.get() == s3.get()); } +TEST(SquareBracketsOperator, Test1) { + shared_ptr pis(new int[10]{0,1,2,3,4,5,6,7,8,9}); + pis[0] = 1; + ASSERT_EQ(pis[0], 1); +} + TEST(SharedReset, Test1) { class contrainer {}; shared_ptr s1 = make_shared(); @@ -87,9 +98,9 @@ TEST(SharedReset, Test1) { TEST(SharedReset, Test2) { class contrainer {}; shared_ptr s1 = make_shared(); - contrainer* p = new contrainer; + contrainer* p = new contrainer; s1.reset(p); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -99,7 +110,7 @@ TEST(SharedReset, Test3) { shared_ptr s1 = make_shared(); contrainer* p = new contrainer; s1.reset(p, std::default_delete()); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -156,5 +167,6 @@ TEST(SharedBoolOperator, Test2) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } \ No newline at end of file From ee97d6f9b2b79ad2e4eb649b4d856de9e5ff7881 Mon Sep 17 00:00:00 2001 From: ChrisBenua Date: Fri, 19 Feb 2021 20:36:19 +0300 Subject: [PATCH 2/5] Implemented shared_ptr and weak_ptr --- .../homework/SharedPointer/CMakeLists.txt | 1 - .../SharedPointer/src/control/control.h | 114 +------ .../SharedPointer/src/shared_ptr/shared_ptr.h | 319 +++--------------- module-1/homework/SharedPointer/tests.cpp | 18 +- 4 files changed, 73 insertions(+), 379 deletions(-) diff --git a/module-1/homework/SharedPointer/CMakeLists.txt b/module-1/homework/SharedPointer/CMakeLists.txt index 90bf5295..624cb834 100644 --- a/module-1/homework/SharedPointer/CMakeLists.txt +++ b/module-1/homework/SharedPointer/CMakeLists.txt @@ -35,7 +35,6 @@ if (CMAKE_VERSION VERSION_LESS 2.8.11) endif() add_subdirectory(src/shared_ptr) -add_subdirectory(src/control) add_executable(runner tests.cpp) target_link_libraries(runner LINK_PUBLIC shared_ptr gtest_main) diff --git a/module-1/homework/SharedPointer/src/control/control.h b/module-1/homework/SharedPointer/src/control/control.h index 34afb16c..55c08056 100644 --- a/module-1/homework/SharedPointer/src/control/control.h +++ b/module-1/homework/SharedPointer/src/control/control.h @@ -1,112 +1,26 @@ #pragma once -#include - - class shared_count { -protected: - std::atomic strong_count; - - virtual ~shared_count() {} -public: - explicit shared_count(size_t count = 0) noexcept: strong_count(count) {} - //delete copy - shared_count(const shared_count& c) = delete; - shared_count(shared_count&& c) = delete; - - void retain_shared() noexcept { - strong_count.fetch_add(1); - } - - bool release_shared() noexcept { - if (strong_count.fetch_sub(1) == 0) { - on_zero_shared(); - return true; - } - return false; - } - - long use_count() const noexcept { - return strong_count + 1; - } + protected: + // Your code goes here... - virtual void on_zero_shared() noexcept = 0; + public: + // Your code goes here... }; class shared_weak_count : public shared_count { -private: - std::atomic weak_count; - -protected: - virtual ~shared_weak_count() {} - -public: - //explicit shared_weak_count(size_t count = 1) noexcept: weak_count(count), shared_count(count) {} - shared_weak_count(size_t weak = 1, size_t strong = 0) noexcept: weak_count(weak), shared_count(strong) {} - - shared_weak_count(const shared_weak_count& c) = delete; - shared_weak_count(shared_weak_count&& c) = delete; - - - void retain_weak() noexcept { - weak_count.fetch_add(1); - } - - void retain_shared() noexcept { - shared_count::retain_shared(); - } - - void release_shared() noexcept { - if (shared_count::release_shared()) { - release_weak(); - } - } - - void release_weak() noexcept { - weak_count.fetch_sub(1); - } - - long use_count() const noexcept { - return shared_count::use_count(); - } - - virtual void on_zero_shared() noexcept = 0; - - virtual shared_weak_count* lock() = 0; -}; - -template -struct __default_deleter { - void operator()(T ptr) noexcept { - delete ptr; - } + private: + // Your code goes here... + + public: + // Your code goes here... }; -template> +template class control_block : public shared_weak_count { -public: - control_block(T _t): ptr(_t), deleter(__default_deleter()) {} - - control_block(T _t, Deleter deleter): ptr(_t), deleter(deleter) {} - - control_block(const control_block& c) = delete; - - control_block(control_block&& c) = delete; - - void on_zero_shared() noexcept override { - deleter(ptr); - } - - shared_weak_count* lock() override { - if (use_count() > 0) { - control_block* res = new control_block(ptr, deleter); - res->retain_shared(); - return res; - } - return nullptr; - } + public: + // Your code goes here... -private: - T ptr; - Deleter deleter; + private: + // Your code goes here... }; diff --git a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h index 7ebbd7fd..416d9890 100644 --- a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h +++ b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h @@ -2,193 +2,76 @@ #include "../control/control.h" -template -struct remove_extent { using type = T; }; - -template -struct remove_extent { using type = T; }; - -template -struct remove_extent { using type = T; }; - // shared_ptr template class weak_ptr; template class shared_ptr { -public: - using element_type = typename remove_extent::type; - - constexpr shared_ptr() noexcept = default; - ~shared_ptr(); - - template - explicit shared_ptr(Y* p); - - template - shared_ptr(Y* p, Deleter deleter) noexcept; - - shared_ptr(const shared_ptr& other) noexcept; - shared_ptr(shared_ptr&& other) noexcept; - - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - template - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - template - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - // Modifiers - void reset() noexcept; - - template - void reset(Y* p) noexcept; - - template - void reset(Y*p, Deleter deleter) noexcept; - - void swap(shared_ptr& other) noexcept; - - // Observers - T* get() const noexcept; - long use_count() const noexcept; - T& operator*() const noexcept; - T* operator->() const noexcept; - element_type& operator[](std::ptrdiff_t idx) const; - explicit operator bool() const noexcept; - - template - friend class weak_ptr; - -private: - - element_type* value_ptr = nullptr; - shared_weak_count* control_ptr = nullptr; + public: + using element_type = T; + + constexpr shared_ptr() noexcept = default; + ~shared_ptr(); + + template + shared_ptr(Y* p); + + template + shared_ptr(Y* p, Deleter deleter) noexcept; + + shared_ptr(const shared_ptr& other) noexcept; + shared_ptr(shared_ptr&& other) noexcept; + + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + template + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + template + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + // Modifiers + void reset() noexcept; + + template + void reset(Y* p) noexcept; + + template + void reset(Y*p, Deleter deleter) noexcept; + + void swap(shared_ptr& other) noexcept; + + // Observers + T* get() const noexcept; + long use_count() const noexcept; + T& operator*() const noexcept; + T* operator->() const noexcept; + element_type& operator[](std::ptrdiff_t idx) const; + explicit operator bool() const noexcept; + + private: + // Your code goes here... }; -template -void shared_ptr::swap(shared_ptr &other) noexcept { - std::swap(control_ptr, other.control_ptr); - std::swap(value_ptr, other.value_ptr); -} - -template -template -shared_ptr::shared_ptr(Y* p): value_ptr(p), control_ptr(new control_block(p)) {} - -template -shared_ptr::~shared_ptr() { - if (control_ptr) { - control_ptr->release_shared(); - } - value_ptr = nullptr; - control_ptr = nullptr; -} - -template -template -shared_ptr::shared_ptr(Y* p, Deleter deleter) noexcept : - value_ptr(p), - control_ptr(new control_block(p, deleter)) - {} - -template -shared_ptr::shared_ptr(const shared_ptr& other) noexcept : - value_ptr(other.value_ptr), - control_ptr(other.control_ptr) -{ - control_ptr->retain_shared(); -} - -template -shared_ptr::shared_ptr(shared_ptr&& other) noexcept : - value_ptr(other.value_ptr), - control_ptr(other.control_ptr) -{ - other.control_ptr = nullptr; - other.value_ptr = nullptr; -} - -template -shared_ptr& shared_ptr::operator=(const shared_ptr& rhs) noexcept { - shared_ptr(rhs).swap(*this); - return *this; -} - -template -shared_ptr& shared_ptr::operator=(shared_ptr&& rhs) noexcept { - shared_ptr(std::forward(rhs)).swap(*this); - return *this; -} - -template -T* shared_ptr::get() const noexcept { - return value_ptr; -} - -template -long shared_ptr::use_count() const noexcept { - return control_ptr == nullptr ? 0 : control_ptr->use_count(); -} - -template -T& shared_ptr::operator*() const noexcept { - return *value_ptr; -} - -template -T* shared_ptr::operator->() const noexcept { - return value_ptr; -} - -template -shared_ptr::operator bool() const noexcept { - return use_count() > 0 && value_ptr != nullptr; -} - -template -typename shared_ptr::element_type& shared_ptr::operator[](std::ptrdiff_t idx) const { - return *(value_ptr + idx); -} - -template -void shared_ptr::reset() noexcept { - value_ptr = nullptr; - if (control_ptr) { - control_ptr->release_shared(); - } -} - -template -template -void shared_ptr::reset(Y* p) noexcept { - shared_ptr(p).swap(*this); -} +// make_shared -template -template -void shared_ptr::reset(Y* p, Deleter deleter) noexcept { - shared_ptr(p, deleter).swap(*this); -} +// Your code goes here... // make_shared -template -shared_ptr make_shared(Args&&... args) { - return shared_ptr(new T(std::forward(args)...)); -} +// shared_ptr + +// Your code goes here... // shared_ptr -// weak_ptr template class weak_ptr { - using element_type = typename remove_extent::type ; + using element_type = T; public: @@ -216,102 +99,12 @@ class weak_ptr { template friend class shared_ptr; public: - element_type* value_ptr = nullptr; - shared_weak_count* control_ptr = nullptr; + // Your code goes here... }; -template -template -weak_ptr::weak_ptr(const shared_ptr& other): value_ptr(other.value_ptr), control_ptr(other.control_ptr) { - if (control_ptr) { - control_ptr->retain_weak(); - } -} - -template -weak_ptr::weak_ptr(const weak_ptr& other) noexcept : - value_ptr(other.value_ptr), control_ptr(other.control_ptr) -{ - if (control_ptr) { - control_ptr->retain_weak(); - } -} - -template -weak_ptr::weak_ptr(weak_ptr&& other) noexcept : - value_ptr(other.value_ptr), - control_ptr(std::move(other.control_ptr)) - { - other.value_ptr = nullptr; - other.control_ptr = nullptr; - } - -template -void weak_ptr::reset() noexcept { - if (control_ptr && value_ptr) { - value_ptr = nullptr; - control_ptr->release_weak(); - control_ptr = nullptr; - } -} - -template -void weak_ptr::swap(weak_ptr& other) noexcept { - std::swap(value_ptr, other.value_ptr); - std::swap(control_ptr, other.control_ptr); -} - -template -bool weak_ptr::expired() noexcept { - return control_ptr == nullptr || control_ptr->use_count() <= 0; -} - -template -shared_ptr weak_ptr::lock() const noexcept { - shared_ptr res; - res.control_ptr = control_ptr ? control_ptr->lock() : control_ptr; - if (res.control_ptr) { - res.value_ptr = this->value_ptr; - } - - return res; -} - -template -template -weak_ptr& weak_ptr::operator=(const shared_ptr& other) { - reset(); - - this->control_ptr = other.control_ptr; - this->value_ptr = other.value_ptr; - if (control_ptr) { - control_ptr->retain_weak(); - } -} - -template -weak_ptr& weak_ptr::operator=(const weak_ptr& other) noexcept { - if (this == other) { - return *this; - } - reset(); - this->value_ptr = other.value_ptr; - this->control_ptr = other.control_ptr; - if (control_ptr) { - control_ptr->retain_weak(); - } - - return *this; -} +// weak_ptr -template -weak_ptr& weak_ptr::operator=(weak_ptr&& other) noexcept { - reset(); - this->value_ptr = other.value_ptr; - this->control_ptr = other.control_ptr; - other.control_ptr = nullptr; - other.value_ptr = nullptr; +// Your code goes here... - return *this; -} +// weak_ptr \ No newline at end of file diff --git a/module-1/homework/SharedPointer/tests.cpp b/module-1/homework/SharedPointer/tests.cpp index b9f0738c..f38a6f6a 100644 --- a/module-1/homework/SharedPointer/tests.cpp +++ b/module-1/homework/SharedPointer/tests.cpp @@ -2,7 +2,6 @@ #include #include "src/shared_ptr/shared_ptr.h" -#include #include "gtest/gtest.h" @@ -64,10 +63,6 @@ TEST(SharedMoveAssignment, Test1) { contrainer* raw_s1 = s1.get(); shared_ptr s2; s2 = std::move(s1); - ASSERT_EQ(s1.use_count(), 0); - ASSERT_EQ(s1.get(), nullptr); - ASSERT_EQ(s2.get(), raw_s1); - ASSERT_EQ(s2.use_count(), 1); ASSERT_TRUE(s1.use_count() == 0 && s1.get() == nullptr && s2.get() == raw_s1 && s2.use_count() == 1); } @@ -82,12 +77,6 @@ TEST(SharedAssignment, Test1) { ASSERT_TRUE(s1.use_count() == 3 && s2.use_count() == 3 && s3.use_count() == 3 && s1.get() == s2.get() && s2.get() == s3.get()); } -TEST(SquareBracketsOperator, Test1) { - shared_ptr pis(new int[10]{0,1,2,3,4,5,6,7,8,9}); - pis[0] = 1; - ASSERT_EQ(pis[0], 1); -} - TEST(SharedReset, Test1) { class contrainer {}; shared_ptr s1 = make_shared(); @@ -98,9 +87,9 @@ TEST(SharedReset, Test1) { TEST(SharedReset, Test2) { class contrainer {}; shared_ptr s1 = make_shared(); - contrainer* p = new contrainer; + contrainer* p = new contrainer; s1.reset(p); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -110,7 +99,7 @@ TEST(SharedReset, Test3) { shared_ptr s1 = make_shared(); contrainer* p = new contrainer; s1.reset(p, std::default_delete()); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -167,6 +156,5 @@ TEST(SharedBoolOperator, Test2) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); } \ No newline at end of file From b83d04b579bfb047fc9aff801c7eb2a3b018ad6d Mon Sep 17 00:00:00 2001 From: ChrisBenua Date: Fri, 19 Feb 2021 20:40:26 +0300 Subject: [PATCH 3/5] Implemented shared_ptr and weak_ptr --- .../SharedPointer/src/control/control.h | 114 ++++++- .../SharedPointer/src/shared_ptr/shared_ptr.h | 323 ++++++++++++++---- module-1/homework/SharedPointer/tests.cpp | 24 +- 3 files changed, 383 insertions(+), 78 deletions(-) diff --git a/module-1/homework/SharedPointer/src/control/control.h b/module-1/homework/SharedPointer/src/control/control.h index 55c08056..34afb16c 100644 --- a/module-1/homework/SharedPointer/src/control/control.h +++ b/module-1/homework/SharedPointer/src/control/control.h @@ -1,26 +1,112 @@ #pragma once +#include + + class shared_count { - protected: - // Your code goes here... +protected: + std::atomic strong_count; + + virtual ~shared_count() {} +public: + explicit shared_count(size_t count = 0) noexcept: strong_count(count) {} + //delete copy + shared_count(const shared_count& c) = delete; + shared_count(shared_count&& c) = delete; + + void retain_shared() noexcept { + strong_count.fetch_add(1); + } + + bool release_shared() noexcept { + if (strong_count.fetch_sub(1) == 0) { + on_zero_shared(); + return true; + } + return false; + } + + long use_count() const noexcept { + return strong_count + 1; + } - public: - // Your code goes here... + virtual void on_zero_shared() noexcept = 0; }; class shared_weak_count : public shared_count { - private: - // Your code goes here... - - public: - // Your code goes here... +private: + std::atomic weak_count; + +protected: + virtual ~shared_weak_count() {} + +public: + //explicit shared_weak_count(size_t count = 1) noexcept: weak_count(count), shared_count(count) {} + shared_weak_count(size_t weak = 1, size_t strong = 0) noexcept: weak_count(weak), shared_count(strong) {} + + shared_weak_count(const shared_weak_count& c) = delete; + shared_weak_count(shared_weak_count&& c) = delete; + + + void retain_weak() noexcept { + weak_count.fetch_add(1); + } + + void retain_shared() noexcept { + shared_count::retain_shared(); + } + + void release_shared() noexcept { + if (shared_count::release_shared()) { + release_weak(); + } + } + + void release_weak() noexcept { + weak_count.fetch_sub(1); + } + + long use_count() const noexcept { + return shared_count::use_count(); + } + + virtual void on_zero_shared() noexcept = 0; + + virtual shared_weak_count* lock() = 0; +}; + +template +struct __default_deleter { + void operator()(T ptr) noexcept { + delete ptr; + } }; -template +template> class control_block : public shared_weak_count { - public: - // Your code goes here... +public: + control_block(T _t): ptr(_t), deleter(__default_deleter()) {} + + control_block(T _t, Deleter deleter): ptr(_t), deleter(deleter) {} + + control_block(const control_block& c) = delete; + + control_block(control_block&& c) = delete; + + void on_zero_shared() noexcept override { + deleter(ptr); + } + + shared_weak_count* lock() override { + if (use_count() > 0) { + control_block* res = new control_block(ptr, deleter); + res->retain_shared(); + return res; + } + return nullptr; + } - private: - // Your code goes here... +private: + T ptr; + Deleter deleter; }; diff --git a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h index 416d9890..4552d520 100644 --- a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h +++ b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h @@ -2,77 +2,194 @@ #include "../control/control.h" +template +struct remove_extent { using type = T; }; + +template +struct remove_extent { using type = T; }; + +template +struct remove_extent { using type = T; }; + // shared_ptr template class weak_ptr; template class shared_ptr { - public: - using element_type = T; - - constexpr shared_ptr() noexcept = default; - ~shared_ptr(); - - template - shared_ptr(Y* p); - - template - shared_ptr(Y* p, Deleter deleter) noexcept; - - shared_ptr(const shared_ptr& other) noexcept; - shared_ptr(shared_ptr&& other) noexcept; - - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - template - shared_ptr& operator=( const shared_ptr& r ) noexcept; - - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - template - shared_ptr& operator=( shared_ptr&& r ) noexcept; - - // Modifiers - void reset() noexcept; - - template - void reset(Y* p) noexcept; - - template - void reset(Y*p, Deleter deleter) noexcept; - - void swap(shared_ptr& other) noexcept; - - // Observers - T* get() const noexcept; - long use_count() const noexcept; - T& operator*() const noexcept; - T* operator->() const noexcept; - element_type& operator[](std::ptrdiff_t idx) const; - explicit operator bool() const noexcept; - - private: - // Your code goes here... +public: + using element_type = typename remove_extent::type; + + constexpr shared_ptr() noexcept = default; + ~shared_ptr(); + + template + explicit shared_ptr(Y* p); + + template + shared_ptr(Y* p, Deleter deleter) noexcept; + + shared_ptr(const shared_ptr& other) noexcept; + shared_ptr(shared_ptr&& other) noexcept; + + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + template + shared_ptr& operator=( const shared_ptr& r ) noexcept; + + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + template + shared_ptr& operator=( shared_ptr&& r ) noexcept; + + // Modifiers + void reset() noexcept; + + template + void reset(Y* p) noexcept; + + template + void reset(Y*p, Deleter deleter) noexcept; + + void swap(shared_ptr& other) noexcept; + + // Observers + T* get() const noexcept; + long use_count() const noexcept; + T& operator*() const noexcept; + T* operator->() const noexcept; + element_type& operator[](std::ptrdiff_t idx) const; + explicit operator bool() const noexcept; + + template + friend class weak_ptr; + +private: + + element_type* value_ptr = nullptr; + shared_weak_count* control_ptr = nullptr; }; -// make_shared +template +void shared_ptr::swap(shared_ptr &other) noexcept { + std::swap(control_ptr, other.control_ptr); + std::swap(value_ptr, other.value_ptr); +} -// Your code goes here... +template +template +shared_ptr::shared_ptr(Y* p): value_ptr(p), control_ptr(new control_block(p)) {} -// make_shared +template +shared_ptr::~shared_ptr() { + if (control_ptr) { + control_ptr->release_shared(); + } + value_ptr = nullptr; + control_ptr = nullptr; +} -// shared_ptr +template +template +shared_ptr::shared_ptr(Y* p, Deleter deleter) noexcept : + value_ptr(p), + control_ptr(new control_block(p, deleter)) + {} + +template +shared_ptr::shared_ptr(const shared_ptr& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(other.control_ptr) +{ + control_ptr->retain_shared(); +} + +template +shared_ptr::shared_ptr(shared_ptr&& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(other.control_ptr) +{ + other.control_ptr = nullptr; + other.value_ptr = nullptr; +} + +template +shared_ptr& shared_ptr::operator=(const shared_ptr& rhs) noexcept { + shared_ptr(rhs).swap(*this); + return *this; +} + +template +shared_ptr& shared_ptr::operator=(shared_ptr&& rhs) noexcept { + shared_ptr(std::forward(rhs)).swap(*this); + return *this; +} + +template +T* shared_ptr::get() const noexcept { + return value_ptr; +} + +template +long shared_ptr::use_count() const noexcept { + return control_ptr == nullptr ? 0 : control_ptr->use_count(); +} + +template +T& shared_ptr::operator*() const noexcept { + return *value_ptr; +} + +template +T* shared_ptr::operator->() const noexcept { + return value_ptr; +} + +template +shared_ptr::operator bool() const noexcept { + return use_count() > 0 && value_ptr != nullptr; +} + +template +typename shared_ptr::element_type& shared_ptr::operator[](std::ptrdiff_t idx) const { + return *(value_ptr + idx); +} + +template +void shared_ptr::reset() noexcept { + value_ptr = nullptr; + if (control_ptr) { + control_ptr->release_shared(); + } +} + +template +template +void shared_ptr::reset(Y* p) noexcept { + shared_ptr(p).swap(*this); +} + +template +template +void shared_ptr::reset(Y* p, Deleter deleter) noexcept { + shared_ptr(p, deleter).swap(*this); +} + +// make_shared +template +shared_ptr make_shared(Args&&... args) { + return shared_ptr(new T(std::forward(args)...)); +} -// Your code goes here... // shared_ptr +// weak_ptr template class weak_ptr { - - using element_type = T; - + + using element_type = typename remove_extent::type ; + public: // Special-member functions @@ -99,12 +216,102 @@ class weak_ptr { template friend class shared_ptr; public: - // Your code goes here... + element_type* value_ptr = nullptr; + shared_weak_count* control_ptr = nullptr; }; -// weak_ptr +template +template +weak_ptr::weak_ptr(const shared_ptr& other): value_ptr(other.value_ptr), control_ptr(other.control_ptr) { + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr::weak_ptr(const weak_ptr& other) noexcept : + value_ptr(other.value_ptr), control_ptr(other.control_ptr) +{ + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr::weak_ptr(weak_ptr&& other) noexcept : + value_ptr(other.value_ptr), + control_ptr(std::move(other.control_ptr)) + { + other.value_ptr = nullptr; + other.control_ptr = nullptr; + } + +template +void weak_ptr::reset() noexcept { + if (control_ptr && value_ptr) { + value_ptr = nullptr; + control_ptr->release_weak(); + control_ptr = nullptr; + } +} + +template +void weak_ptr::swap(weak_ptr& other) noexcept { + std::swap(value_ptr, other.value_ptr); + std::swap(control_ptr, other.control_ptr); +} + +template +bool weak_ptr::expired() noexcept { + return control_ptr == nullptr || control_ptr->use_count() <= 0; +} -// Your code goes here... +template +shared_ptr weak_ptr::lock() const noexcept { + shared_ptr res; + res.control_ptr = control_ptr ? control_ptr->lock() : control_ptr; + if (res.control_ptr) { + res.value_ptr = this->value_ptr; + } + + return res; +} + +template +template +weak_ptr& weak_ptr::operator=(const shared_ptr& other) { + reset(); + + this->control_ptr = other.control_ptr; + this->value_ptr = other.value_ptr; + if (control_ptr) { + control_ptr->retain_weak(); + } +} + +template +weak_ptr& weak_ptr::operator=(const weak_ptr& other) noexcept { + if (this == other) { + return *this; + } + reset(); + this->value_ptr = other.value_ptr; + this->control_ptr = other.control_ptr; + if (control_ptr) { + control_ptr->retain_weak(); + } + + return *this; +} + +template +weak_ptr& weak_ptr::operator=(weak_ptr&& other) noexcept { + reset(); + this->value_ptr = other.value_ptr; + this->control_ptr = other.control_ptr; + other.control_ptr = nullptr; + other.value_ptr = nullptr; -// weak_ptr \ No newline at end of file + return *this; +} diff --git a/module-1/homework/SharedPointer/tests.cpp b/module-1/homework/SharedPointer/tests.cpp index f38a6f6a..44cbfd2d 100644 --- a/module-1/homework/SharedPointer/tests.cpp +++ b/module-1/homework/SharedPointer/tests.cpp @@ -2,6 +2,7 @@ #include #include "src/shared_ptr/shared_ptr.h" +#include #include "gtest/gtest.h" @@ -63,6 +64,10 @@ TEST(SharedMoveAssignment, Test1) { contrainer* raw_s1 = s1.get(); shared_ptr s2; s2 = std::move(s1); + ASSERT_EQ(s1.use_count(), 0); + ASSERT_EQ(s1.get(), nullptr); + ASSERT_EQ(s2.get(), raw_s1); + ASSERT_EQ(s2.use_count(), 1); ASSERT_TRUE(s1.use_count() == 0 && s1.get() == nullptr && s2.get() == raw_s1 && s2.use_count() == 1); } @@ -73,10 +78,16 @@ TEST(SharedAssignment, Test1) { shared_ptr s3; s2 = s1; s3 = s2; - + ASSERT_TRUE(s1.use_count() == 3 && s2.use_count() == 3 && s3.use_count() == 3 && s1.get() == s2.get() && s2.get() == s3.get()); } +TEST(SquareBracketsOperator, Test1) { + shared_ptr pis(new int[10]{0,1,2,3,4,5,6,7,8,9}); + pis[0] = 1; + ASSERT_EQ(pis[0], 1); +} + TEST(SharedReset, Test1) { class contrainer {}; shared_ptr s1 = make_shared(); @@ -87,9 +98,9 @@ TEST(SharedReset, Test1) { TEST(SharedReset, Test2) { class contrainer {}; shared_ptr s1 = make_shared(); - contrainer* p = new contrainer; + contrainer* p = new contrainer; s1.reset(p); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -99,7 +110,7 @@ TEST(SharedReset, Test3) { shared_ptr s1 = make_shared(); contrainer* p = new contrainer; s1.reset(p, std::default_delete()); - + ASSERT_TRUE(s1.get() == p && s1.use_count() == 1); } @@ -111,7 +122,7 @@ TEST(SharedUseCount, Test1) { { shared_ptr s3 = s2; } - + ASSERT_TRUE(s1.use_count() == 2 && s2.use_count() == 2 && s1.get() == s2.get()); } @@ -122,7 +133,7 @@ TEST(SharedSwap, Test1) { auto raw_s1 = s1.get(); auto raw_s3 = s3.get(); s1.swap(s3); - + ASSERT_TRUE(s1.use_count() == 1 && s2.use_count() == 2 && s3.use_count() == 2 && s2.get() == s3.get() && s2.get() == raw_s1 && s1.get() == raw_s3); } @@ -156,5 +167,6 @@ TEST(SharedBoolOperator, Test2) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } \ No newline at end of file From b0bc57fdbce21df3e85685bbb4dd025c213daa77 Mon Sep 17 00:00:00 2001 From: ChrisBenua Date: Sat, 20 Feb 2021 16:25:07 +0300 Subject: [PATCH 4/5] fix weak cnt --- module-1/homework/SharedPointer/src/control/control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-1/homework/SharedPointer/src/control/control.h b/module-1/homework/SharedPointer/src/control/control.h index 34afb16c..ccf0b008 100644 --- a/module-1/homework/SharedPointer/src/control/control.h +++ b/module-1/homework/SharedPointer/src/control/control.h @@ -42,7 +42,7 @@ class shared_weak_count : public shared_count { public: //explicit shared_weak_count(size_t count = 1) noexcept: weak_count(count), shared_count(count) {} - shared_weak_count(size_t weak = 1, size_t strong = 0) noexcept: weak_count(weak), shared_count(strong) {} + shared_weak_count(size_t weak = 0, size_t strong = 0) noexcept: weak_count(weak), shared_count(strong) {} shared_weak_count(const shared_weak_count& c) = delete; shared_weak_count(shared_weak_count&& c) = delete; From ae0b9f0ad68ec7b51854ee6554a05f468acb65af Mon Sep 17 00:00:00 2001 From: ChrisBenua Date: Sat, 20 Feb 2021 16:33:38 +0300 Subject: [PATCH 5/5] added weak_ptr destructor --- .../SharedPointer/src/shared_ptr/shared_ptr.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h index 4552d520..07feba08 100644 --- a/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h +++ b/module-1/homework/SharedPointer/src/shared_ptr/shared_ptr.h @@ -203,7 +203,7 @@ class weak_ptr { weak_ptr& operator=(const weak_ptr& other) noexcept; weak_ptr& operator=(weak_ptr&& other) noexcept; - ~weak_ptr() = default; + ~weak_ptr(); // Modifiers void reset() noexcept; @@ -288,6 +288,8 @@ weak_ptr& weak_ptr::operator=(const shared_ptr& other) { if (control_ptr) { control_ptr->retain_weak(); } + + return *this; } template @@ -315,3 +317,10 @@ weak_ptr& weak_ptr::operator=(weak_ptr&& other) noexcept { return *this; } + +template +weak_ptr::~weak_ptr() { + if (control_ptr) { + control_ptr->release_weak(); + } +}