#include #include #include #include #include #include #include "smart_pointers.h" //template //using SharedPtr = std::shared_ptr; // //template //using WeakPtr = std::weak_ptr; // //#define makeShared std::make_shared //#define allocateShared std::allocate_shared // //template //using EnableSharedFromThis = std::enable_shared_from_this; struct Base { virtual ~Base() {} }; struct Derived: public Base { static int constructed; static int destructerd; Derived() { ++constructed; } ~Derived() { ++destructerd; } }; int Derived::constructed = 0; int Derived::destructerd = 0; void test_shared_ptr() { using std::vector; auto first_ptr = SharedPtr>(new vector(1'000'000)); auto second_ptr = SharedPtr>(new vector(10)); first_ptr.reset(new vector()); second_ptr.reset(); SharedPtr>().swap(first_ptr); assert(second_ptr.get() == nullptr); assert(second_ptr.get() == nullptr); for (int k = 0; k < 2; ++k) { vector> ptrs; for (int i = 0; i < 100'000; ++i) { int* p = new int(rand() % 99'999); ptrs.push_back(SharedPtr(p)); } std::sort(ptrs.begin(), ptrs.end(), [](auto&& x, auto&& y){return *x < *y;}); for (int i = 0; i + 1 < 100'000; ++i) { assert(*(ptrs[i]) <= *(ptrs[i+1])); } while (!ptrs.empty()) { ptrs.pop_back(); } } // test const { const SharedPtr sp(new int(42)); assert(sp.use_count() == 1); assert(*sp.get() == 42); assert(*sp == 42); } } struct Node; struct Next { SharedPtr shared; WeakPtr weak; Next(const SharedPtr& shared): shared(shared) {} Next(const WeakPtr& weak): weak(weak) {} }; struct Node { static int constructed; static int destructed; int value; Next next; Node(int value): value(value), next(SharedPtr()) { ++constructed; } Node(int value, const SharedPtr& next): value(value), next(next) { ++constructed; } Node(int value, const WeakPtr& next): value(value), next(next) { ++constructed; } ~Node() { ++destructed; } }; int Node::constructed = 0; int Node::destructed = 0; SharedPtr getCyclePtr(int cycleSize) { SharedPtr head(new Node(0)); SharedPtr prev(head); for (int i = 1; i < cycleSize; ++i) { SharedPtr current(new Node(i)); prev->next.shared = current; prev = current; // std::cout << prev.use_count() << '\n'; } //prev->next.shared.~SharedPtr(); //new (&prev->next.weak) WeakPtr(head); prev->next.weak = head; //prev->next.isLast = true; return head; } int allocated = 0; int deallocated = 0; int allocate_called = 0; int deallocate_called = 0; int new_called = 0; int delete_called = 0; void test_weak_ptr() { auto sp = SharedPtr(new int(23)); WeakPtr weak = sp; { auto shared = SharedPtr(new int(42)); weak = shared; assert(weak.use_count() == 1); assert(!weak.expired()); } assert(weak.use_count() == 0); assert(weak.expired()); weak = sp; auto wp = weak; assert(weak.use_count() == 1); assert(wp.use_count() == 1); auto wwp = std::move(weak); //assert(weak.use_count() == 0); assert(wwp.use_count() == 1); auto ssp = wwp.lock(); assert(sp.use_count() == 2); sp = ssp; ssp = sp; assert(ssp.use_count() == 2); sp = std::move(ssp); assert(sp.use_count() == 1); ssp.reset(); // nothing should happen sp.reset(); unsigned int useless_value = 0; for (int i = 0; i < 100'000; ++i) { SharedPtr head = getCyclePtr(8); SharedPtr nextHead = head->next.shared; assert(nextHead.use_count() == 2); useless_value += 19'937 * i * nextHead.use_count(); head.reset(); assert(nextHead.use_count() == 1); } assert(Node::constructed == 800'000); assert(Node::destructed == 800'000); // test inheritance { SharedPtr dsp(new Derived()); SharedPtr bsp = dsp; WeakPtr wdsp = dsp; WeakPtr wbsp = dsp; WeakPtr wwbsp = wdsp; assert(dsp.use_count() == 2); bsp = std::move(dsp); assert(bsp.use_count() == 1); bsp.reset(); assert(wdsp.expired()); assert(wbsp.expired()); assert(wwbsp.expired()); } assert(Derived::constructed == Derived::destructerd); // test const new_called = 0; delete_called = 0; { SharedPtr sp(new int(42)); const WeakPtr wp(sp); assert(!wp.expired()); auto ssp = wp.lock(); } assert(new_called == 2); assert(delete_called == 2); } struct NeitherDefaultNorCopyConstructible { NeitherDefaultNorCopyConstructible() = delete; NeitherDefaultNorCopyConstructible(const NeitherDefaultNorCopyConstructible&) = delete; NeitherDefaultNorCopyConstructible& operator=(const NeitherDefaultNorCopyConstructible&) = delete; NeitherDefaultNorCopyConstructible(NeitherDefaultNorCopyConstructible&&) = default; NeitherDefaultNorCopyConstructible& operator=(NeitherDefaultNorCopyConstructible&&) = default; explicit NeitherDefaultNorCopyConstructible(int x): x(x) {} int x; }; struct Accountant { static int constructed; static int destructed; Accountant() { ++constructed; } Accountant(const Accountant&) { ++constructed; } ~Accountant() { ++destructed; } }; int Accountant::constructed = 0; int Accountant::destructed = 0; void* operator new(size_t n) { ++new_called; auto t = std::malloc(n); return t; } void operator delete(void* ptr) { ++delete_called; std::free(ptr); } struct VerySpecialType {}; void* operator new(size_t n, VerySpecialType) { return std::malloc(n); } void operator delete(void* ptr, VerySpecialType) { std::free(ptr); } template struct MyAllocator { using value_type = T; MyAllocator() = default; template MyAllocator(const MyAllocator&) {} T* allocate(size_t n) { ++allocate_called; allocated += n * sizeof(T);; return (T*) ::operator new(n * sizeof(T), VerySpecialType()); } void deallocate(T* p, size_t n) { ++deallocate_called; deallocated += n * sizeof(T); ::operator delete((void*)p, VerySpecialType()); } }; void test_make_allocate_shared() { new_called = 0; delete_called = 0; { auto sp = makeShared( NeitherDefaultNorCopyConstructible(0)); WeakPtr wp = sp; auto ssp = sp; sp.reset(); assert(!wp.expired()); ssp.reset(); assert(wp.expired()); } new_called = 0; delete_called = 0; { auto sp = makeShared(); assert(Accountant::constructed == 1); WeakPtr wp = sp; auto ssp = sp; sp.reset(); assert(Accountant::constructed == 1); assert(Accountant::destructed == 0); assert(!wp.expired()); ssp.reset(); assert(Accountant::destructed == 1); Accountant::constructed = 0; Accountant::destructed = 0; } new_called = 0; delete_called = 0; { MyAllocator alloc; auto sp = allocateShared( alloc, NeitherDefaultNorCopyConstructible(0)); int count = allocated; assert(allocated > 0); assert(allocate_called == 1); WeakPtr wp = sp; auto ssp = sp; sp.reset(); assert(count == allocated); assert(deallocated == 0); assert(!wp.expired()); ssp.reset(); assert(count == allocated); } assert(allocated == deallocated); assert(allocate_called == 1); assert(deallocate_called == 1); allocated = 0; deallocated = 0; allocate_called = 0; deallocate_called = 0; { MyAllocator alloc; auto sp = allocateShared(alloc); int count = allocated; assert(allocated > 0); assert(allocate_called == 1); assert(Accountant::constructed == 1); WeakPtr wp = sp; auto ssp = sp; sp.reset(); assert(count == allocated); assert(deallocated == 0); assert(Accountant::constructed == 1); assert(Accountant::destructed == 0); assert(!wp.expired()); ssp.reset(); assert(count == allocated); } assert(allocated == deallocated); assert(Accountant::constructed == 1); assert(Accountant::destructed == 1); assert(allocate_called == 1); assert(deallocate_called == 1); assert(new_called == 0); assert(delete_called == 0); } //struct Enabled: public EnableSharedFromThis { // SharedPtr get_shared() { // return shared_from_this(); // } //}; //void test_enable_shared_from_this() { // { // Enabled e; // bool caught = false; // try { // e.get_shared(); // } catch (...) { // caught = true; // } // assert(caught); // } // // auto esp = makeShared(); // // auto& e = *esp; // auto sp = e.get_shared(); // // assert(sp.use_count() == 2); // // esp.reset(); // assert(sp.use_count() == 1); // // sp.reset(); //} struct A { static int deleted; virtual ~A() { ++deleted; } }; int A::deleted = 0; struct A1: public A { static int deleted; virtual ~A1() { ++deleted; } }; int A1::deleted = 0; struct A2: public A { static int deleted; virtual ~A2() { ++deleted; } }; int A2::deleted = 0; struct A11: public A1 { static int deleted; virtual ~A11() { ++deleted; } }; int A11::deleted = 0; struct A12: public A1 { static int deleted; virtual ~A12() { ++deleted; } }; int A12::deleted = 0; struct A21: public A2 { static int deleted; virtual ~A21() { ++deleted; } }; int A21::deleted = 0; struct A22: public A2 { static int deleted; virtual ~A22() { ++deleted; } }; int A22::deleted = 0; int destroy_called; template struct MyAlloc { using value_type = T; MyAlloc() = default; template MyAlloc(const MyAlloc&) {} void destroy(T* p) { ++destroy_called; p->~T(); } T* allocate(size_t n) { ++allocate_called; allocated += n * sizeof(T);; return (T*) ::operator new(n * sizeof(T), VerySpecialType()); } void deallocate(T* p, size_t n) { ++deallocate_called; deallocated += n * sizeof(T); ::operator delete((void*)p, VerySpecialType()); } }; void my_test_inheritance_destroy() { { SharedPtr a22 = allocateShared>(MyAlloc()); SharedPtr a2 = a22; SharedPtr a = a2; assert(a.use_count() == 3); a22.reset(); a.reset(); a = allocateShared>(MyAlloc()); WeakPtr wa = a; WeakPtr wwa = wa; a.reset(new A2()); } assert(A22::deleted == 1); assert(A21::deleted == 1); } void my_test_custom_deleter(); struct T { ~T() { std::cout << "~" << std::endl; } }; int main() { using namespace std; std::allocator all; SharedPtr p(all.allocate(1)); // p.reset(); // SharedPtr p; p.reset(new T); p.reset(new T); p.reset(new T); p.reset(new T); p.reset(new T); p.reset(); std::cout << "alsdkfj" << endl; // return 0; static_assert(!std::is_base_of_v, SharedPtr>, "don't try to use std smart pointers"); // static_assert(!std::is_base_of_v, WeakPtr>, // "don't try to use std smart pointers"); // test_shared_ptr(); std::cout << "1/5 passed" << std::endl; test_weak_ptr(); std::cout << "2/5 passed" << std::endl; test_make_allocate_shared(); std::cout << "3/5 passed" << std::endl; std::cout << "starting my tests" << std::endl; my_test_inheritance_destroy(); std::cout << "4/5 passed" << std::endl; my_test_custom_deleter(); std::cout << "5/5 passed" << std::endl; std::cout << "now it should work" << std::endl; // test_enable_shared_from_this(); } template struct MyDeletor { static int deleted; void operator()(T* x) { ::delete x; ++deleted; } }; template int MyDeletor::deleted = 0; void my_test_custom_deleter() { { SharedPtr p(new Accountant(), MyDeletor()); SharedPtr pp = std::move(p); std::cout << pp.use_count() << std::endl; SharedPtr h = pp; std::cout << h.use_count() << std::endl; // p = allocateShared>(MyAlloc()); } std::cout << delete_called << std::endl; assert(delete_called == 4); assert(destroy_called == 3); destroy_called = 0; { auto* smth = new Accountant(); SharedPtr p(smth, MyDeletor(), MyAlloc()); SharedPtr pp = std::move(p); SharedPtr h = pp; p = allocateShared>(MyAlloc()); } assert(delete_called == 5); assert(destroy_called == 1); }