diff --git a/homework/shared_ptr/shared_ptr.hpp b/homework/shared_ptr/shared_ptr.hpp new file mode 100644 index 00000000..c74f9bd0 --- /dev/null +++ b/homework/shared_ptr/shared_ptr.hpp @@ -0,0 +1,124 @@ +#ifndef SHARED_PRT_H_ +#define SHARED_PRT_H_ + +#include +#include + +namespace my { + +template +struct ControlBlock { + std::atomic shared_refs; + std::atomic weak_refs; + std::function deleter; +}; + +template +auto default_deleter = [](Type1* p) { delete p; }; + +template +class shared_ptr { +private: + Type* ptr_; + ControlBlock* ctrl_block_; + +public: + shared_ptr(Type* ptr = nullptr, std::function d = default_deleter) + : ptr_(ptr), ctrl_block_(new ControlBlock{1, 0, d}) { + } + + shared_ptr(const shared_ptr& other) + : ptr_(other.ptr_), ctrl_block_(other.ctrl_block_) { + ctrl_block_->shared_refs++; + } + + shared_ptr(shared_ptr&& other) + : ptr_(other.ptr_), ctrl_block_(other.ctrl_block_) { + other.ptr_ = nullptr; + other.ctrl_block_ = nullptr; + } + + ~shared_ptr() { + if (ctrl_block_) { + ctrl_block_->shared_refs--; + if (ctrl_block_->shared_refs == 0) { + ctrl_block_->deleter(ptr_); + + if (ctrl_block_->weak_refs == 0) { + delete ctrl_block_; + } + } + } + } + + shared_ptr& operator=(shared_ptr& other) { + if (ptr_ != other.ptr_) { + if (ctrl_block_->shared_refs == 1u) { + ctrl_block_->deleter(ptr_); + delete ctrl_block_; + } else { + ctrl_block_->shared_refs--; + } + } + ptr_ = other.ptr_; + ctrl_block_ = other.ctrl_block_; + ctrl_block_->shared_refs++; + return *this; + } + + shared_ptr& operator=(shared_ptr&& other) { + if (ptr_ != other.ptr_) { + if (ctrl_block_->shared_refs == 1u) { + ctrl_block_->deleter(ptr_); + delete ctrl_block_; + } else { + ctrl_block_->shared_refs--; + } + } + ptr_ = other.ptr_; + ctrl_block_ = other.ctrl_block_; + other.ptr_ = nullptr; + other.ctrl_block_ = nullptr; + return *this; + } + + Type* operator->() { + return ptr_; + } + + Type& operator*() { + return *ptr_; + } + + explicit operator bool() const { + return (ptr_ != nullptr); + } + + size_t use_count() { + return ctrl_block_->shared_refs; + } + + Type* get() { + return ptr_; + } + + void reset(Type* ptr = nullptr, std::function d = default_deleter) { + if (ptr_ && ctrl_block_->shared_refs == 1) { + ctrl_block_->deleter(ptr_); + ptr_ = ptr; + ctrl_block_->deleter = d; + } else if (!ptr_) { + if (ctrl_block_) { + ptr_ = ptr; + ctrl_block_->shared_refs = 1; + } else { + ctrl_block_ = new ControlBlock{1, 0, d}; + ptr_ = ptr; + } + } else { + } + } +}; + +} // namespace my +#endif /* SHARED_PRT_H_*/ diff --git a/homework/shared_ptr/shared_ptr_tests.cpp b/homework/shared_ptr/shared_ptr_tests.cpp new file mode 100644 index 00000000..5e97ba16 --- /dev/null +++ b/homework/shared_ptr/shared_ptr_tests.cpp @@ -0,0 +1,31 @@ +#include +#include "shared_ptr.hpp" + +template class my::shared_ptr; + +TEST(SharedPtr, shouldCreateSharedPtrWithInitialValue) { + my::shared_ptr p{new int(5)}; + ASSERT_EQ(*p, 5); +} + +TEST(SharedPtr, shouldCreateWithCopyConstructor) { + my::shared_ptr p{new int(5)}; + my::shared_ptr p2(p); + + ASSERT_EQ(p.get(), p2.get()); + ASSERT_EQ(p.operator->(), p2.get()); + ASSERT_EQ(p.operator->(), p2.operator->()); + ASSERT_EQ(p.use_count(), 2); +} + +TEST(SharedPtr, shouldCreateWithMoveConstructor) { + my::shared_ptr p{new int(5)}; + my::shared_ptr p2(std::move(p)); + + ASSERT_EQ(p.get(), nullptr); + ASSERT_EQ(p2.use_count(), 1); + p2.reset(); + ASSERT_EQ(p2.get(), nullptr); + p2.reset(new int(6)); + ASSERT_EQ(*p2, 6); +} \ No newline at end of file