From ccaaffb44a7f98e68a6763675a2cc8ae02635d6e Mon Sep 17 00:00:00 2001 From: deadbeef Date: Sat, 25 Feb 2017 12:56:20 -0800 Subject: [PATCH] Adding rtc::Unretained to allow avoiding rtc::Bind reference capture. In some rare circumstances, capturing a reference may be undesired. For example, when creating an asynchronous task owned by the object itself, the object may not need or want this task to keep itself alive. BUG=None Review-Url: https://codereview.webrtc.org/2711113008 Cr-Commit-Position: refs/heads/master@{#16840} --- webrtc/base/bind.h | 74 ++++++++++++++++++++++++++++++++---- webrtc/base/bind_unittest.cc | 2 + 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/webrtc/base/bind.h b/webrtc/base/bind.h index 397a4d5c87..94eb164986 100644 --- a/webrtc/base/bind.h +++ b/webrtc/base/bind.h @@ -17,6 +17,10 @@ // ref-counted method object or any arguments passed by pointer, and calling the // functor with a destroyed object will surely do bad things. // +// To prevent the method object from being captured as a scoped_refptr<>, you +// can use Unretained. But this should only be done when absolutely necessary, +// and when the caller knows the extra reference isn't needed. +// // Example usage: // struct Foo { // int Test1() { return 42; } @@ -125,8 +129,23 @@ struct PointerType { T*>::type type; }; +template +class UnretainedWrapper { + public: + explicit UnretainedWrapper(T* o) : ptr_(o) {} + T* get() const { return ptr_; } + + private: + T* ptr_; +}; + } // namespace detail +template +static inline detail::UnretainedWrapper Unretained(T* o) { + return detail::UnretainedWrapper(o); +} + template class MethodFunctor { public: @@ -150,6 +169,31 @@ class MethodFunctor { typename std::tuple::type...> args_; }; +template +class UnretainedMethodFunctor { + public: + UnretainedMethodFunctor(MethodT method, + detail::UnretainedWrapper object, + Args... args) + : method_(method), object_(object.get()), args_(args...) {} + R operator()() const { + return CallMethod(typename sequence_generator::type()); + } + + private: + // Use sequence_generator (see template_util.h) to expand an + // UnretainedMethodFunctor with 2 arguments to (std::get<0>(args_), + // std::get<1>(args_)), for instance. + template + R CallMethod(sequence) const { + return (object_->*method_)(std::get(args_)...); + } + + MethodT method_; + ObjectT* object_; + typename std::tuple::type...> args_; +}; + template class Functor { public: @@ -183,6 +227,24 @@ MethodFunctor Bind( args...); } +template +MethodFunctor Bind( + FP_T(method), + const scoped_refptr& object, + typename detail::identity::type... args) { + return MethodFunctor(method, object.get(), + args...); +} + +template +UnretainedMethodFunctor Bind( + FP_T(method), + detail::UnretainedWrapper object, + typename detail::identity::type... args) { + return UnretainedMethodFunctor( + method, object, args...); +} + #undef FP_T #define FP_T(x) R (ObjectT::*x)(Args...) const @@ -194,17 +256,13 @@ MethodFunctor Bind( return MethodFunctor(method, object, args...); } - -#undef FP_T -#define FP_T(x) R (ObjectT::*x)(Args...) - template -MethodFunctor Bind( +UnretainedMethodFunctor Bind( FP_T(method), - const scoped_refptr& object, + detail::UnretainedWrapper object, typename detail::identity::type... args) { - return MethodFunctor(method, object.get(), - args...); + return UnretainedMethodFunctor( + method, object, args...); } #undef FP_T diff --git a/webrtc/base/bind_unittest.cc b/webrtc/base/bind_unittest.cc index 33315912bf..c97a555d87 100644 --- a/webrtc/base/bind_unittest.cc +++ b/webrtc/base/bind_unittest.cc @@ -87,6 +87,8 @@ EXPECT_IS_CAPTURED_AS_PTR(double); EXPECT_IS_CAPTURED_AS_PTR(A); EXPECT_IS_CAPTURED_AS_PTR(D); EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*); +EXPECT_IS_CAPTURED_AS_PTR( + decltype(Unretained>)); EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface); EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);