diff options
Diffstat (limited to 'include/gatekeeper/UniquePtr.h')
-rw-r--r-- | include/gatekeeper/UniquePtr.h | 168 |
1 files changed, 154 insertions, 14 deletions
diff --git a/include/gatekeeper/UniquePtr.h b/include/gatekeeper/UniquePtr.h index 77ff99f..9f81466 100644 --- a/include/gatekeeper/UniquePtr.h +++ b/include/gatekeeper/UniquePtr.h @@ -17,7 +17,7 @@ #ifndef GATEKEEPER_UNIQUE_PTR_H_included #define GATEKEEPER_UNIQUE_PTR_H_included -#include <stdlib.h> // For NULL. +#include <stddef.h> // for size_t namespace gatekeeper { @@ -50,9 +50,32 @@ struct DefaultDelete<T[]> { // UniquePtr<C> c(new C); template <typename T, typename D = DefaultDelete<T> > class UniquePtr { + template<typename U, typename UD> + friend + class UniquePtr; public: + UniquePtr() : mPtr(nullptr) {} // Construct a new UniquePtr, taking ownership of the given raw pointer. - explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { + explicit UniquePtr(T* ptr) : mPtr(ptr) { + } + // NOLINTNEXTLINE(google-explicit-constructor) + UniquePtr(const decltype(nullptr)&) : mPtr(nullptr) {} + + UniquePtr(UniquePtr && other): mPtr(other.mPtr) { + other.mPtr = nullptr; + } + + template <typename U> + // NOLINTNEXTLINE(google-explicit-constructor) + UniquePtr(UniquePtr<U>&& other) : mPtr(other.mPtr) { + other.mPtr = nullptr; + } + UniquePtr& operator=(UniquePtr && other) { + if (&other != this) { + reset(); + mPtr = other.release(); + } + return *this; } ~UniquePtr() { @@ -64,18 +87,21 @@ public: T* operator->() const { return mPtr; } T* get() const { return mPtr; } + // NOLINTNEXTLINE(google-explicit-constructor) + operator bool() const { return mPtr != nullptr; } + // Returns the raw pointer and hands over ownership to the caller. // The pointer will not be deleted by UniquePtr. T* release() __attribute__((warn_unused_result)) { T* result = mPtr; - mPtr = NULL; + mPtr = nullptr; return result; } // Takes ownership of the given raw pointer. // If this smart pointer previously owned a different raw pointer, that // raw pointer will be freed. - void reset(T* ptr = NULL) { + void reset(T* ptr = nullptr) { if (ptr != mPtr) { D()(mPtr); mPtr = ptr; @@ -90,9 +116,8 @@ private: template <typename T2> bool operator==(const UniquePtr<T2>& p) const; template <typename T2> bool operator!=(const UniquePtr<T2>& p) const; - // Disallow copy and assignment. - UniquePtr(const UniquePtr&); - void operator=(const UniquePtr&); + UniquePtr(const UniquePtr&) = delete; + UniquePtr & operator=(const UniquePtr&) = delete; }; // Partial specialization for array types. Like std::unique_ptr, this removes @@ -100,7 +125,21 @@ private: template <typename T, typename D> class UniquePtr<T[], D> { public: - explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { + UniquePtr() : mPtr(nullptr) {} + explicit UniquePtr(T* ptr) : mPtr(ptr) { + } + // NOLINTNEXTLINE(google-explicit-constructor) + UniquePtr(const decltype(nullptr)&) : mPtr(nullptr) {} + + UniquePtr(UniquePtr && other): mPtr(other.mPtr) { + other.mPtr = nullptr; + } + UniquePtr& operator=(UniquePtr && other) { + if (&other != this) { + reset(); + mPtr = other.release(); + } + return *this; } ~UniquePtr() { @@ -114,11 +153,14 @@ public: T* release() __attribute__((warn_unused_result)) { T* result = mPtr; - mPtr = NULL; + mPtr = nullptr; return result; } - void reset(T* ptr = NULL) { + // NOLINTNEXTLINE(google-explicit-constructor) + operator bool() const { return mPtr != nullptr; } + + void reset(T* ptr = nullptr) { if (ptr != mPtr) { D()(mPtr); mPtr = ptr; @@ -128,10 +170,108 @@ public: private: T* mPtr; - // Disallow copy and assignment. - UniquePtr(const UniquePtr&); - void operator=(const UniquePtr&); + UniquePtr(const UniquePtr&) = delete; + UniquePtr & operator=(const UniquePtr&) = delete; }; -} //namespace gatekeeper +} // namespace gatekeeper + +#if UNIQUE_PTR_TESTS + +// Run these tests with: +// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out + +#include <stdio.h> +using namespace keymaster; + +static void assert(bool b) { + if (!b) { + fprintf(stderr, "FAIL\n"); + abort(); + } + fprintf(stderr, "OK\n"); +} +static int cCount = 0; +struct C { + C() { ++cCount; } + ~C() { --cCount; } +}; +static bool freed = false; +struct Freer { + void operator()(int* p) { + assert(*p == 123); + free(p); + freed = true; + } +}; + +int main(int argc, char* argv[]) { + // + // UniquePtr<T> tests... + // + + // Can we free a single object? + { + UniquePtr<C> c(new C); + assert(cCount == 1); + } + assert(cCount == 0); + // Does release work? + C* rawC; + { + UniquePtr<C> c(new C); + assert(cCount == 1); + rawC = c.release(); + } + assert(cCount == 1); + delete rawC; + // Does reset work? + { + UniquePtr<C> c(new C); + assert(cCount == 1); + c.reset(new C); + assert(cCount == 1); + } + assert(cCount == 0); + + // + // UniquePtr<T[]> tests... + // + + // Can we free an array? + { + UniquePtr<C[]> cs(new C[4]); + assert(cCount == 4); + } + assert(cCount == 0); + // Does release work? + { + UniquePtr<C[]> c(new C[4]); + assert(cCount == 4); + rawC = c.release(); + } + assert(cCount == 4); + delete[] rawC; + // Does reset work? + { + UniquePtr<C[]> c(new C[4]); + assert(cCount == 4); + c.reset(new C[2]); + assert(cCount == 2); + } + assert(cCount == 0); + + // + // Custom deleter tests... + // + assert(!freed); + { + UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int)))); + *i = 123; + } + assert(freed); + return 0; +} +#endif + #endif // GATEKEEPER_UNIQUE_PTR_H_included |