From ba5ea44bad712d454504f55bbcd347494ba9c188 Mon Sep 17 00:00:00 2001 From: kwiberg Date: Mon, 25 Apr 2016 18:08:40 -0700 Subject: [PATCH] Make rtc::scoped_ptr a type alias for std::unique_ptr There's also one fixup that could neither be done before or after landing the type alias CL: changing the FunctorMessageHandler template specialization for rtc::scoped_ptr to be for std::unique_ptr instead. (Having one specialization for scoped_ptr and one for unique_ptr doesn't work when the types are the same, and having just the scoped_ptr specialization doesn't work when scoped_ptr is a type alias. I'm sure there's some template metaprogramming magic that could solve the problem, but it's easy enough to just make the change in this CL instead.) BUG=webrtc:5520 Review URL: https://codereview.webrtc.org/1797463002 Cr-Commit-Position: refs/heads/master@{#12499} --- webrtc/base/messagehandler.h | 8 +- webrtc/base/scoped_ptr.h | 601 +---------------------------------- 2 files changed, 16 insertions(+), 593 deletions(-) diff --git a/webrtc/base/messagehandler.h b/webrtc/base/messagehandler.h index b55b229a6d..90563e4083 100644 --- a/webrtc/base/messagehandler.h +++ b/webrtc/base/messagehandler.h @@ -50,18 +50,18 @@ class FunctorMessageHandler : public MessageHandler { ReturnT result_; }; -// Specialization for rtc::scoped_ptr. +// Specialization for std::unique_ptr. template -class FunctorMessageHandler, FunctorT> +class FunctorMessageHandler, FunctorT> : public MessageHandler { public: explicit FunctorMessageHandler(const FunctorT& functor) : functor_(functor) {} virtual void OnMessage(Message* msg) { result_ = std::move(functor_()); } - rtc::scoped_ptr result() { return std::move(result_); } + std::unique_ptr result() { return std::move(result_); } private: FunctorT functor_; - rtc::scoped_ptr result_; + std::unique_ptr result_; }; // Specialization for ReturnT of void. diff --git a/webrtc/base/scoped_ptr.h b/webrtc/base/scoped_ptr.h index b7e94989e5..db5ef9e696 100644 --- a/webrtc/base/scoped_ptr.h +++ b/webrtc/base/scoped_ptr.h @@ -8,85 +8,19 @@ * be found in the AUTHORS file in the root of the source tree. */ -// Borrowed from Chromium's src/base/memory/scoped_ptr.h. - -// Scopers help you manage ownership of a pointer, helping you easily manage 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[]. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr foo(new Foo("wee")); -// } // foo goes out of scope, releasing the pointer with it. -// -// { -// scoped_ptr 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. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr foo(new Foo[100]); -// foo.get()->Method(); // Foo::Method on the 0th element. -// foo[10].Method(); // Foo::Method on the 10th element. -// } -// -// These scopers also implement part of the functionality of C++11 unique_ptr -// in that they are "movable but not copyable." You can use the scopers in the -// parameter and return types of functions to signify ownership transfer in to -// and out of a function. When calling a function that has a scoper as the -// argument type, it must be called with the result of calling std::move on an -// analogous scoper, or another function that generates a temporary; passing by -// copy will NOT work. Here is an example using scoped_ptr: -// -// void TakesOwnership(scoped_ptr arg) { -// // Do something with arg -// } -// scoped_ptr CreateFoo() { -// // No need for calling std::move because we are constructing a temporary -// // for the return value. -// return scoped_ptr(new Foo("new")); -// } -// scoped_ptr PassThru(scoped_ptr arg) { -// return std::move(arg); -// } -// -// { -// scoped_ptr ptr(new Foo("yay")); // ptr manages Foo("yay"). -// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay"). -// scoped_ptr ptr2 = CreateFoo(); // ptr2 owns the return Foo. -// scoped_ptr ptr3 = // ptr3 now owns what was in ptr2. -// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr. -// } -// -// Notice that if you do not call std::move when returning from PassThru(), or -// when invoking TakesOwnership(), the code will not compile because scopers -// are not copyable; they only implement move semantics which require calling -// std::move to signify a destructive transfer of state. CreateFoo() is -// different though because we are constructing a temporary on the return line -// and thus can avoid needing to call std::move. +// This entire file is deprecated, and will be removed in XXXX 2016. Use +// std::unique_ptr instead! #ifndef WEBRTC_BASE_SCOPED_PTR_H__ #define WEBRTC_BASE_SCOPED_PTR_H__ -// This is an implementation designed to match the anticipated future TR2 -// implementation of the scoped_ptr class. +// All these #includes are left to maximize backwards compatibility. #include #include #include -#include // For std::swap(). +#include #include #include @@ -96,531 +30,20 @@ namespace rtc { -// Function object which deletes its parameter, which must be a pointer. -// If C is an array type, invokes 'delete[]' on the parameter; otherwise, -// invokes 'delete'. The default deleter for scoped_ptr. -template -struct DefaultDeleter { - DefaultDeleter() {} - template DefaultDeleter(const DefaultDeleter& other) { - // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor - // if U* is implicitly convertible to T* and U is not an array type. - // - // Correct implementation should use SFINAE to disable this - // constructor. However, since there are no other 1-argument constructors, - // using a static_assert based on is_convertible<> and requiring - // complete types is simpler and will cause compile failures for equivalent - // misuses. - // - // Note, the is_convertible check also ensures that U is not an - // array. T is guaranteed to be a non-array, so any U* where U is an array - // cannot convert to T*. - enum { T_must_be_complete = sizeof(T) }; - enum { U_must_be_complete = sizeof(U) }; - static_assert(rtc::is_convertible::value, - "U* must implicitly convert to T*"); - } - inline void operator()(T* ptr) const { - enum { type_must_be_complete = sizeof(T) }; - delete ptr; - } -}; - -// Specialization of DefaultDeleter for array types. -template -struct DefaultDeleter { - inline void operator()(T* ptr) const { - enum { type_must_be_complete = sizeof(T) }; - delete[] ptr; - } - - private: - // Disable this operator for any U != T because it is undefined to execute - // an array delete when the static type of the array mismatches the dynamic - // type. - // - // References: - // C++98 [expr.delete]p3 - // http://cplusplus.github.com/LWG/lwg-defects.html#938 - template void operator()(U* array) const; -}; - -template -struct DefaultDeleter { - // Never allow someone to declare something like scoped_ptr. - static_assert(sizeof(T) == -1, "do not use array with size as type"); -}; - -// Function object which invokes 'free' on its parameter, which must be -// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: -// -// scoped_ptr foo_ptr( -// static_cast(malloc(sizeof(int)))); -struct FreeDeleter { - inline void operator()(void* ptr) const { - free(ptr); - } -}; - -namespace internal { +template > +using scoped_ptr = std::unique_ptr; +// These used to convert between rtc::scoped_ptr and std::unique_ptr. Now they +// are no-ops. template -struct ShouldAbortOnSelfReset { - template - static rtc::internal::NoType Test(const typename U::AllowSelfReset*); - - template - static rtc::internal::YesType Test(...); - - static const bool value = - sizeof(Test(0)) == sizeof(rtc::internal::YesType); -}; - -// Minimal implementation of the core logic of scoped_ptr, suitable for -// reuse in both scoped_ptr and its specializations. -template -class scoped_ptr_impl { - public: - explicit scoped_ptr_impl(T* p) : data_(p) {} - - // Initializer for deleters that have data parameters. - scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} - - // Templated constructor that destructively takes the value from another - // scoped_ptr_impl. - template - scoped_ptr_impl(scoped_ptr_impl* other) - : data_(other->release(), other->get_deleter()) { - // We do not support move-only deleters. We could modify our move - // emulation to have rtc::subtle::move() and rtc::subtle::forward() - // functions that are imperfect emulations of their C++11 equivalents, - // but until there's a requirement, just assume deleters are copyable. - } - - template - void TakeState(scoped_ptr_impl* other) { - // See comment in templated constructor above regarding lack of support - // for move-only deleters. - reset(other->release()); - get_deleter() = other->get_deleter(); - } - - ~scoped_ptr_impl() { - if (data_.ptr != nullptr) { - // Not using get_deleter() saves one function call in non-optimized - // builds. - static_cast(data_)(data_.ptr); - } - } - - void reset(T* p) { - // This is a self-reset, which is no longer allowed for default deleters: - // https://crbug.com/162971 - assert(!ShouldAbortOnSelfReset::value || p == nullptr || p != data_.ptr); - - // Note that running data_.ptr = p can lead to undefined behavior if - // get_deleter()(get()) deletes this. In order to prevent this, reset() - // should update the stored pointer before deleting its old value. - // - // However, changing reset() to use that behavior may cause current code to - // break in unexpected ways. If the destruction of the owned object - // dereferences the scoped_ptr when it is destroyed by a call to reset(), - // then it will incorrectly dispatch calls to |p| rather than the original - // value of |data_.ptr|. - // - // During the transition period, set the stored pointer to nullptr while - // deleting the object. Eventually, this safety check will be removed to - // prevent the scenario initially described from occurring and - // http://crbug.com/176091 can be closed. - T* old = data_.ptr; - data_.ptr = nullptr; - if (old != nullptr) - static_cast(data_)(old); - data_.ptr = p; - } - - T* get() const { return data_.ptr; } - - D& get_deleter() { return data_; } - const D& get_deleter() const { return data_; } - - void swap(scoped_ptr_impl& p2) { - // Standard swap idiom: 'using std::swap' ensures that std::swap is - // present in the overload set, but we call swap unqualified so that - // any more-specific overloads can be used, if available. - using std::swap; - swap(static_cast(data_), static_cast(p2.data_)); - swap(data_.ptr, p2.data_.ptr); - } - - T* release() { - T* old_ptr = data_.ptr; - data_.ptr = nullptr; - return old_ptr; - } - - T** accept() { - reset(nullptr); - return &(data_.ptr); - } - - T** use() { - return &(data_.ptr); - } - - private: - // Needed to allow type-converting constructor. - template friend class scoped_ptr_impl; - - // Use the empty base class optimization to allow us to have a D - // member, while avoiding any space overhead for it when D is an - // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good - // discussion of this technique. - struct Data : public D { - explicit Data(T* ptr_in) : ptr(ptr_in) {} - Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} - T* ptr; - }; - - Data data_; - - RTC_DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); -}; - -} // namespace internal - -// A scoped_ptr is like a T*, except that the destructor of scoped_ptr -// automatically deletes the pointer it holds (if any). -// That is, scoped_ptr owns the T object that it points to. -// Like a T*, a scoped_ptr may hold either nullptr or a pointer to a T -// object. Also like T*, scoped_ptr is thread-compatible, and once you -// dereference it, you get the thread safety guarantees of T. -// -// The size of scoped_ptr is small. On most compilers, when using the -// DefaultDeleter, sizeof(scoped_ptr) == sizeof(T*). Custom deleters will -// increase the size proportional to whatever state they need to have. See -// comments inside scoped_ptr_impl<> for details. -// -// Current implementation targets having a strict subset of C++11's -// unique_ptr<> features. Known deficiencies include not supporting move-only -// deleters, function pointers as deleters, and deleters with reference -// types. -template > -class scoped_ptr { - - // TODO(ajm): If we ever import RefCountedBase, this check needs to be - // enabled. - //static_assert(rtc::internal::IsNotRefCounted::value, - // "T is refcounted type and needs scoped refptr"); - - public: - // The element and deleter types. - typedef T element_type; - typedef D deleter_type; - - // Constructor. Defaults to initializing with nullptr. - scoped_ptr() : impl_(nullptr) {} - - // Constructor. Takes ownership of p. - explicit scoped_ptr(element_type* p) : impl_(p) {} - - // Constructor. Allows initialization of a stateful deleter. - scoped_ptr(element_type* p, const D& d) : impl_(p, d) {} - - // Constructor. Allows construction from a nullptr. - scoped_ptr(std::nullptr_t) : impl_(nullptr) {} - - // Constructor. Allows construction from a scoped_ptr rvalue for a - // convertible type and deleter. - // - // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct - // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor - // has different post-conditions if D is a reference type. Since this - // implementation does not support deleters with reference type, - // we do not need a separate move constructor allowing us to avoid one - // use of SFINAE. You only need to care about this if you modify the - // implementation of scoped_ptr. - template - scoped_ptr(scoped_ptr&& other) - : impl_(&other.impl_) { - static_assert(!rtc::is_array::value, "U cannot be an array"); - } - - // operator=. Allows assignment from a scoped_ptr rvalue for a convertible - // type and deleter. - // - // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from - // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated - // form has different requirements on for move-only Deleters. Since this - // implementation does not support move-only Deleters, we do not need a - // separate move assignment operator allowing us to avoid one use of SFINAE. - // You only need to care about this if you modify the implementation of - // scoped_ptr. - template - scoped_ptr& operator=(scoped_ptr&& rhs) { - static_assert(!rtc::is_array::value, "U cannot be an array"); - impl_.TakeState(&rhs.impl_); - return *this; - } - - // operator=. Allows assignment from a nullptr. Deletes the currently owned - // object, if any. - scoped_ptr& operator=(std::nullptr_t) { - reset(); - return *this; - } - - // Deleted copy constructor and copy assignment, to make the type move-only. - scoped_ptr(const scoped_ptr& other) = delete; - scoped_ptr& operator=(const scoped_ptr& other) = delete; - - // Reset. Deletes the currently owned object, if any. - // Then takes ownership of a new object, if given. - void reset(element_type* p = nullptr) { impl_.reset(p); } - - // Accessors to get the owned object. - // operator* and operator-> will assert() if there is no current object. - element_type& operator*() const { - assert(impl_.get() != nullptr); - return *impl_.get(); - } - element_type* operator->() const { - assert(impl_.get() != nullptr); - return impl_.get(); - } - element_type* get() const { return impl_.get(); } - - // Access to the deleter. - deleter_type& get_deleter() { return impl_.get_deleter(); } - const deleter_type& get_deleter() const { return impl_.get_deleter(); } - - // Allow scoped_ptr to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - // - // Note that this trick is only safe when the == and != operators - // are declared explicitly, as otherwise "scoped_ptr1 == - // scoped_ptr2" will compile but do the wrong thing (i.e., convert - // to Testable and then do the comparison). - private: - typedef rtc::internal::scoped_ptr_impl - scoped_ptr::*Testable; - - public: - operator Testable() const { - return impl_.get() ? &scoped_ptr::impl_ : nullptr; - } - - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(const element_type* p) const { return impl_.get() == p; } - bool operator!=(const element_type* p) const { return impl_.get() != p; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is the current pointer held by this object. If this object - // holds a nullptr, the return value is nullptr. After this operation, this - // object will hold a nullptr, and will not own the object any more. - element_type* release() WARN_UNUSED_RESULT { - return impl_.release(); - } - - // Delete the currently held pointer and return a pointer - // to allow overwriting of the current pointer address. - element_type** accept() WARN_UNUSED_RESULT { - return impl_.accept(); - } - - // Return a pointer to the current pointer address. - element_type** use() WARN_UNUSED_RESULT { - return impl_.use(); - } - - private: - // Needed to reach into |impl_| in the constructor. - template friend class scoped_ptr; - rtc::internal::scoped_ptr_impl impl_; - - // Forbidden for API compatibility with std::unique_ptr. - explicit scoped_ptr(int disallow_construction_from_null); - - // Forbid comparison of scoped_ptr types. If U != T, it totally - // doesn't make sense, and if U == T, it still doesn't make sense - // because you should never have the same object owned by two different - // scoped_ptrs. - template bool operator==(scoped_ptr const& p2) const; - template bool operator!=(scoped_ptr const& p2) const; -}; - -template -class scoped_ptr { - public: - // The element and deleter types. - typedef T element_type; - typedef D deleter_type; - - // Constructor. Defaults to initializing with nullptr. - scoped_ptr() : impl_(nullptr) {} - - // Constructor. Stores the given array. Note that the argument's type - // must exactly match T*. In particular: - // - it cannot be a pointer to a type derived from T, because it is - // inherently unsafe in the general case to access an array through a - // pointer whose dynamic type does not match its static type (eg., if - // T and the derived types had different sizes access would be - // incorrectly calculated). Deletion is also always undefined - // (C++98 [expr.delete]p3). If you're doing this, fix your code. - // - it cannot be const-qualified differently from T per unique_ptr spec - // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting - // to work around this may use implicit_cast(). - // However, because of the first bullet in this comment, users MUST - // NOT use implicit_cast() to upcast the static type of the array. - explicit scoped_ptr(element_type* array) : impl_(array) {} - - // Constructor. Allows construction from a nullptr. - scoped_ptr(std::nullptr_t) : impl_(nullptr) {} - - // Constructor. Allows construction from a scoped_ptr rvalue. - scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {} - - // operator=. Allows assignment from a scoped_ptr rvalue. - scoped_ptr& operator=(scoped_ptr&& rhs) { - impl_.TakeState(&rhs.impl_); - return *this; - } - - // operator=. Allows assignment from a nullptr. Deletes the currently owned - // array, if any. - scoped_ptr& operator=(std::nullptr_t) { - reset(); - return *this; - } - - // Deleted copy constructor and copy assignment, to make the type move-only. - scoped_ptr(const scoped_ptr& other) = delete; - scoped_ptr& operator=(const scoped_ptr& other) = delete; - - // Reset. Deletes the currently owned array, if any. - // Then takes ownership of a new object, if given. - void reset(element_type* array = nullptr) { impl_.reset(array); } - - // Accessors to get the owned array. - element_type& operator[](size_t i) const { - assert(impl_.get() != nullptr); - return impl_.get()[i]; - } - element_type* get() const { return impl_.get(); } - - // Access to the deleter. - deleter_type& get_deleter() { return impl_.get_deleter(); } - const deleter_type& get_deleter() const { return impl_.get_deleter(); } - - // Allow scoped_ptr to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - private: - typedef rtc::internal::scoped_ptr_impl - scoped_ptr::*Testable; - - public: - operator Testable() const { - return impl_.get() ? &scoped_ptr::impl_ : nullptr; - } - - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(element_type* array) const { return impl_.get() == array; } - bool operator!=(element_type* array) const { return impl_.get() != array; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is the current pointer held by this object. If this object - // holds a nullptr, the return value is nullptr. After this operation, this - // object will hold a nullptr, and will not own the object any more. - element_type* release() WARN_UNUSED_RESULT { - return impl_.release(); - } - - // Delete the currently held pointer and return a pointer - // to allow overwriting of the current pointer address. - element_type** accept() WARN_UNUSED_RESULT { - return impl_.accept(); - } - - // Return a pointer to the current pointer address. - element_type** use() WARN_UNUSED_RESULT { - return impl_.use(); - } - - private: - // Force element_type to be a complete type. - enum { type_must_be_complete = sizeof(element_type) }; - - // Actually hold the data. - rtc::internal::scoped_ptr_impl impl_; - - // Disable initialization from any type other than element_type*, by - // providing a constructor that matches such an initialization, but is - // private and has no definition. This is disabled because it is not safe to - // call delete[] on an array whose static type does not match its dynamic - // type. - template explicit scoped_ptr(U* array); - explicit scoped_ptr(int disallow_construction_from_null); - - // Disable reset() from any type other than element_type*, for the same - // reasons as the constructor above. - template void reset(U* array); - void reset(int disallow_reset_from_null); - - // Forbid comparison of scoped_ptr types. If U != T, it totally - // doesn't make sense, and if U == T, it still doesn't make sense - // because you should never have the same object owned by two different - // scoped_ptrs. - template bool operator==(scoped_ptr const& p2) const; - template bool operator!=(scoped_ptr const& p2) const; -}; - -template -void swap(rtc::scoped_ptr& p1, rtc::scoped_ptr& p2) { - p1.swap(p2); -} - -// Convert between the most common kinds of scoped_ptr and unique_ptr. -template -std::unique_ptr ScopedToUnique(scoped_ptr sp) { - return std::unique_ptr(sp.release()); +std::unique_ptr ScopedToUnique(std::unique_ptr up) { + return up; } template -scoped_ptr UniqueToScoped(std::unique_ptr up) { - return scoped_ptr(up.release()); +std::unique_ptr UniqueToScoped(std::unique_ptr up) { + return up; } } // namespace rtc -template -bool operator==(T* p1, const rtc::scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -bool operator!=(T* p1, const rtc::scoped_ptr& p2) { - return p1 != p2.get(); -} - -// A function to convert T* into scoped_ptr -// Doing e.g. make_scoped_ptr(new FooBarBaz(arg)) is a shorter notation -// for scoped_ptr >(new FooBarBaz(arg)) -template -rtc::scoped_ptr rtc_make_scoped_ptr(T* ptr) { - return rtc::scoped_ptr(ptr); -} - #endif // #ifndef WEBRTC_BASE_SCOPED_PTR_H__