diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/scoped_ptr.h | 487 |
1 files changed, 278 insertions, 209 deletions
diff --git a/src/common/scoped_ptr.h b/src/common/scoped_ptr.h index 2dbc40df..d137c186 100644 --- a/src/common/scoped_ptr.h +++ b/src/common/scoped_ptr.h @@ -1,231 +1,285 @@ -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001, 2002 Peter Dimov +// Copyright 2013 Google Inc. All Rights Reserved. // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. // - -// scoped_ptr mimics a built-in pointer except that it guarantees deletion -// of the object pointed to, either on destruction of the scoped_ptr or via -// an explicit reset(). scoped_ptr is a simple solution for simple needs; -// use shared_ptr or std::auto_ptr if your needs are more complex. - -// *** NOTE *** -// If your scoped_ptr is a class member of class FOO pointing to a -// forward declared type BAR (as shown below), then you MUST use a non-inlined -// version of the destructor. The destructor of a scoped_ptr (called from -// FOO's destructor) must have a complete definition of BAR in order to -// destroy it. Example: +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Scopers help you manage ownership of a pointer, helping you easily manage the +// a pointer within a scope, and automatically destroying the pointer at the +// end of a scope. There are two main classes you will use, which correspond +// to the operators new/delete and new[]/delete[]. // -// -- foo.h -- -// class BAR; +// Example usage (scoped_ptr): +// { +// scoped_ptr<Foo> foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. // -// class FOO { -// public: -// FOO(); -// ~FOO(); // Required for sources that instantiate class FOO to compile! -// -// private: -// scoped_ptr<BAR> bar_; -// }; +// { +// scoped_ptr<Foo> foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. // -// -- foo.cc -- -// #include "foo.h" -// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition. - -// scoped_ptr_malloc added by Google -// When one of these goes out of scope, instead of doing a delete or -// delete[], it calls free(). scoped_ptr_malloc<char> is likely to see -// much more use than any other specializations. - -// release() added by Google -// Use this to conditionally transfer ownership of a heap-allocated object -// to the caller, usually on method success. +// Example usage (scoped_array): +// { +// scoped_array<Foo> foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } #ifndef COMMON_SCOPED_PTR_H_ #define COMMON_SCOPED_PTR_H_ -#include <cstddef> // for std::ptrdiff_t -#include <assert.h> // for assert -#include <stdlib.h> // for free() decl +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class, and its closely-related brethren, +// scoped_array, scoped_ptr_malloc. + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> namespace google_breakpad { -template <typename T> +// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr<T> owns the T object that it points to. +// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr<T> is thread-compatible, and once you +// dereference it, you get the threadsafety guarantees of T. +// +// The size of a scoped_ptr is small: +// sizeof(scoped_ptr<C>) == sizeof(C*) +template <class C> class scoped_ptr { - private: - - T* ptr; - - scoped_ptr(scoped_ptr const &); - scoped_ptr & operator=(scoped_ptr const &); - public: - typedef T element_type; + // The element type + typedef C element_type; - explicit scoped_ptr(T* p = 0): ptr(p) {} + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with new. + explicit scoped_ptr(C* p = NULL) : ptr_(p) { } + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. ~scoped_ptr() { - typedef char type_must_be_complete[sizeof(T)]; - delete ptr; + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; } - void reset(T* p = 0) { - typedef char type_must_be_complete[sizeof(T)]; - - if (ptr != p) { - delete ptr; - ptr = p; + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != ptr_) { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + ptr_ = p; } } - T& operator*() const { - assert(ptr != 0); - return *ptr; - } - - T* operator->() const { - assert(ptr != 0); - return ptr; + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; } - - bool operator==(T* p) const { - return ptr == p; - } - - bool operator!=(T* p) const { - return ptr != p; + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; } - - T* get() const { - return ptr; - } - - void swap(scoped_ptr & b) { - T* tmp = b.ptr; - b.ptr = ptr; - ptr = tmp; + C* get() const { return ptr_; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return ptr_ == p; } + bool operator!=(C* p) const { return ptr_ != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + C* tmp = ptr_; + ptr_ = p2.ptr_; + p2.ptr_ = tmp; } - T* release() { - T* tmp = ptr; - ptr = 0; - return tmp; + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = ptr_; + ptr_ = NULL; + return retVal; } private: + C* ptr_; + + // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't + // make sense, and if C2 == C, it still doesn't make sense because you should + // never have the same object owned by two different scoped_ptrs. + template <class C2> bool operator==(scoped_ptr<C2> const& p2) const; + template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const; - // no reason to use these: each scoped_ptr should have its own object - template <typename U> bool operator==(scoped_ptr<U> const& p) const; - template <typename U> bool operator!=(scoped_ptr<U> const& p) const; + // Disallow evil constructors + scoped_ptr(const scoped_ptr&); + void operator=(const scoped_ptr&); }; -template<typename T> inline -void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) { - a.swap(b); +// Free functions +template <class C> +void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) { + p1.swap(p2); } -template<typename T> inline -bool operator==(T* p, const scoped_ptr<T>& b) { - return p == b.get(); +template <class C> +bool operator==(C* p1, const scoped_ptr<C>& p2) { + return p1 == p2.get(); } -template<typename T> inline -bool operator!=(T* p, const scoped_ptr<T>& b) { - return p != b.get(); +template <class C> +bool operator!=(C* p1, const scoped_ptr<C>& p2) { + return p1 != p2.get(); } -// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to -// is guaranteed, either on destruction of the scoped_array or via an explicit -// reset(). Use shared_array or std::vector if your needs are more complex. - -template<typename T> +// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr<C>, a scoped_array<C> either points to an object +// or is NULL. A scoped_array<C> owns the object that it points to. +// scoped_array<T> is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array<C>) == sizeof(C*) +template <class C> class scoped_array { - private: - - T* ptr; - - scoped_array(scoped_array const &); - scoped_array & operator=(scoped_array const &); - public: - typedef T element_type; + // The element type + typedef C element_type; - explicit scoped_array(T* p = 0) : ptr(p) {} + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. ~scoped_array() { - typedef char type_must_be_complete[sizeof(T)]; - delete[] ptr; + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; } - void reset(T* p = 0) { - typedef char type_must_be_complete[sizeof(T)]; - - if (ptr != p) { - delete [] ptr; - ptr = p; + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; } } - T& operator[](std::ptrdiff_t i) const { - assert(ptr != 0); + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](ptrdiff_t i) const { assert(i >= 0); - return ptr[i]; - } - - bool operator==(T* p) const { - return ptr == p; + assert(array_ != NULL); + return array_[i]; } - bool operator!=(T* p) const { - return ptr != p; + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; } - T* get() const { - return ptr; + // Comparison operators. + // These return whether two scoped_array refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return array_ == p; } + bool operator!=(C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; } - void swap(scoped_array & b) { - T* tmp = b.ptr; - b.ptr = ptr; - ptr = tmp; - } - - T* release() { - T* tmp = ptr; - ptr = 0; - return tmp; + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; } private: + C* array_; - // no reason to use these: each scoped_array should have its own object - template <typename U> bool operator==(scoped_array<U> const& p) const; - template <typename U> bool operator!=(scoped_array<U> const& p) const; + // Forbid comparison of different scoped_array types. + template <class C2> bool operator==(scoped_array<C2> const& p2) const; + template <class C2> bool operator!=(scoped_array<C2> const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); }; -template<class T> inline -void swap(scoped_array<T>& a, scoped_array<T>& b) { - a.swap(b); +// Free functions +template <class C> +void swap(scoped_array<C>& p1, scoped_array<C>& p2) { + p1.swap(p2); } -template<typename T> inline -bool operator==(T* p, const scoped_array<T>& b) { - return p == b.get(); +template <class C> +bool operator==(C* p1, const scoped_array<C>& p2) { + return p1 == p2.get(); } -template<typename T> inline -bool operator!=(T* p, const scoped_array<T>& b) { - return p != b.get(); +template <class C> +bool operator!=(C* p1, const scoped_array<C>& p2) { + return p1 != p2.get(); } - // This class wraps the c library function free() in a class that can be // passed as a template argument to scoped_ptr_malloc below. class ScopedPtrMallocFree { @@ -238,95 +292,110 @@ class ScopedPtrMallocFree { // scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a // second template argument, the functor used to free the object. -template<typename T, typename FreeProc = ScopedPtrMallocFree> +template<class C, class FreeProc = ScopedPtrMallocFree> class scoped_ptr_malloc { - private: - - T* ptr; - - scoped_ptr_malloc(scoped_ptr_malloc const &); - scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); - public: - typedef T element_type; + // The element type + typedef C element_type; - explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with an allocator that matches the + // Free functor. For the default Free functor, this is malloc, calloc, or + // realloc. + explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} + // Destructor. If there is a C object, call the Free functor. ~scoped_ptr_malloc() { - typedef char type_must_be_complete[sizeof(T)]; - free_((void*) ptr); + reset(); } - void reset(T* p = 0) { - typedef char type_must_be_complete[sizeof(T)]; - - if (ptr != p) { - free_((void*) ptr); - ptr = p; + // Reset. Calls the Free functor on the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (ptr_ != p) { + FreeProc free_proc; + free_proc(ptr_); + ptr_ = p; } } - T& operator*() const { - assert(ptr != 0); - return *ptr; + // Get the current object. + // operator* and operator-> will cause an assert() failure if there is + // no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; } - T* operator->() const { - assert(ptr != 0); - return ptr; + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; } - bool operator==(T* p) const { - return ptr == p; + C* get() const { + return ptr_; } - bool operator!=(T* p) const { - return ptr != p; + // Comparison operators. + // These return whether a scoped_ptr_malloc and a plain pointer refer + // to the same object, not just to two different but equal objects. + // For compatibility with the boost-derived implementation, these + // take non-const arguments. + bool operator==(C* p) const { + return ptr_ == p; } - T* get() const { - return ptr; + bool operator!=(C* p) const { + return ptr_ != p; } + // Swap two scoped pointers. void swap(scoped_ptr_malloc & b) { - T* tmp = b.ptr; - b.ptr = ptr; - ptr = tmp; + C* tmp = b.ptr_; + b.ptr_ = ptr_; + ptr_ = tmp; } - T* release() { - T* tmp = ptr; - ptr = 0; + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* tmp = ptr_; + ptr_ = NULL; return tmp; } private: + C* ptr_; // no reason to use these: each scoped_ptr_malloc should have its own object - template <typename U, typename GP> - bool operator==(scoped_ptr_malloc<U, GP> const& p) const; - template <typename U, typename GP> - bool operator!=(scoped_ptr_malloc<U, GP> const& p) const; - - static FreeProc const free_; + template <class C2, class GP> + bool operator==(scoped_ptr_malloc<C2, GP> const& p) const; + template <class C2, class GP> + bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const; + + // Disallow evil constructors + scoped_ptr_malloc(const scoped_ptr_malloc&); + void operator=(const scoped_ptr_malloc&); }; -template<typename T, typename FP> -FP const scoped_ptr_malloc<T,FP>::free_ = FP(); - -template<typename T, typename FP> inline -void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) { +template<class C, class FP> inline +void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) { a.swap(b); } -template<typename T, typename FP> inline -bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) { +template<class C, class FP> inline +bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) { return p == b.get(); } -template<typename T, typename FP> inline -bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) { +template<class C, class FP> inline +bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) { return p != b.get(); } |