From 676eec88cc79c89efe707b5e03c9b6a4ce380ac7 Mon Sep 17 00:00:00 2001 From: karl Date: Thu, 28 Nov 2019 18:53:02 +0100 Subject: [PATCH] Minor improvements --- main.cpp | 171 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 79 deletions(-) diff --git a/main.cpp b/main.cpp index 410fd4a..4d9e598 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,95 @@ #include +#include +/// Holds unique ownership of a pointed to object and destroys it automatically +template +class UniquePtr { +public: + /// Constructor without deleter + explicit UniquePtr(T *object) : object(object), deleter([](T *object) -> void { delete object; }) { + assert(object != nullptr); + } + + /// Constructor with custom deleter + /// Note that the custom deleter may not get a valid object (it could be a nullptr due to resetting, moving, etc) + UniquePtr(T *object, void (*deleter)(T *)) : object(object), deleter(deleter) { + assert(object != nullptr); + assert(deleter != nullptr); + } + + /// Copy constructor + /// Shouldn't be used, since the pointer wouldn't be unique otherwise + UniquePtr(const UniquePtr &other) = delete; + + /// Move constructor + UniquePtr(UniquePtr &&other) : object(other.object), deleter(other.deleter) { + other.object = nullptr; + } + + /// Copy assignment operator + /// Shouldn't be used, since the pointer wouldn't be unique otherwise + UniquePtr &operator=(const UniquePtr &) = delete; + + /// Move assignment operator + UniquePtr &operator=(UniquePtr &&other) { + object = other.object; + deleter = other.deleter; + + other.object = nullptr; + } + + /// Destructor + virtual ~UniquePtr() { + deleter(object); + } + + T operator*() const { + assert(object != nullptr); + + return *object; + } + + operator bool() const { + return object != nullptr; + } + + T *operator->() const { + assert(object != nullptr); + + return object; + } + + /// Release ownership of the owned object and return the pointer to it + T *Release() { + T *returnObject = object; + object = nullptr; + + return returnObject; + } + + /// Reset the internal pointer to null + void Reset() { + deleter(object); + + object = nullptr; + } + + /// Swaps the currently owned object with another + void Swap(T *other) { + // TODO: This isn't really a "swap" but more of a "replace" - a proper swap would be std::swap(object, other); + // Not sure which one should be implemented, since I find this version more practical... + deleter(object); + + object = other; + } + +private: + T *object; + + void (*deleter)(T *); +}; + +/// Simple object for testing constructor, destructor calls and potential memory leaks class TestObject { public: TestObject() { @@ -30,86 +120,9 @@ private: int TestObject::instanceCount = 0; -/// Holds unique ownership of a pointed to object and destroys it automatically -template -class UniquePtr { -public: - /// Constructor without deleter - explicit UniquePtr(T *object) : object(object), deleter(nullptr) {} - - /// Constructor with deleter - UniquePtr(T *object, void (*deleter)(T*)) : object(object), deleter(deleter) {} - - /// Copy constructor - /// Shouldn't be used, since the pointer wouldn't be unique otherwise - UniquePtr(const UniquePtr &other) = delete; - - /// Move constructor - UniquePtr(UniquePtr &&other) : object(other.object), deleter(other.deleter) { - other.object = nullptr; - } - - /// Copy assignment operator - UniquePtr &operator=(const UniquePtr &) = delete; - - /// Move assignment operator - /// Shouldn't be used, since the pointer wouldn't be unique otherwise - UniquePtr &operator=(UniquePtr &&) = delete; - - /// Destructor - virtual ~UniquePtr() { - deleteObject(); - } - - T operator*() const { - return *object; - } - - operator bool() const { - return object != nullptr; - } - - T *operator->() const { - return object; - } - - /// Release ownership of the owned object and return the pointer to it - T *Release() { - T *returnObject = object; - object = nullptr; - - return returnObject; - } - - /// Reset the internal pointer to null - void Reset() { - deleteObject(); - - object = nullptr; - } - - /// Swaps the currently owned object with another - void Swap(T *other) { - deleteObject(); - - object = other; - } - -private: - T *object; - void (*deleter)(T*); - - void deleteObject() { - if (deleter != nullptr && object != nullptr) { - deleter(object); - } else { - delete object; - } - } -}; - void customTestObjectDeleter(TestObject *object) { std::cout << "Custom deleter" << std::endl; + delete object; } @@ -126,7 +139,7 @@ int main() { std::cout << "Swapping for new object" << std::endl; pointer.Swap(new TestObject()); - std::cout << "Move constructing new pointer" << std::endl; + std::cout << "Move assigning new pointer" << std::endl; UniquePtr pointer2 = UniquePtr(std::move(pointer)); std::cout << "Constructing pointer with custom deleter" << std::endl;