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}
This commit is contained in:
deadbeef 2017-02-25 12:56:20 -08:00 committed by Commit bot
parent 37510bf094
commit ccaaffb44a
2 changed files with 68 additions and 8 deletions

View File

@ -17,6 +17,10 @@
// ref-counted method object or any arguments passed by pointer, and calling the // ref-counted method object or any arguments passed by pointer, and calling the
// functor with a destroyed object will surely do bad things. // 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: // Example usage:
// struct Foo { // struct Foo {
// int Test1() { return 42; } // int Test1() { return 42; }
@ -125,8 +129,23 @@ struct PointerType {
T*>::type type; T*>::type type;
}; };
template <typename T>
class UnretainedWrapper {
public:
explicit UnretainedWrapper(T* o) : ptr_(o) {}
T* get() const { return ptr_; }
private:
T* ptr_;
};
} // namespace detail } // namespace detail
template <typename T>
static inline detail::UnretainedWrapper<T> Unretained(T* o) {
return detail::UnretainedWrapper<T>(o);
}
template <class ObjectT, class MethodT, class R, typename... Args> template <class ObjectT, class MethodT, class R, typename... Args>
class MethodFunctor { class MethodFunctor {
public: public:
@ -150,6 +169,31 @@ class MethodFunctor {
typename std::tuple<typename std::remove_reference<Args>::type...> args_; typename std::tuple<typename std::remove_reference<Args>::type...> args_;
}; };
template <class ObjectT, class MethodT, class R, typename... Args>
class UnretainedMethodFunctor {
public:
UnretainedMethodFunctor(MethodT method,
detail::UnretainedWrapper<ObjectT> object,
Args... args)
: method_(method), object_(object.get()), args_(args...) {}
R operator()() const {
return CallMethod(typename sequence_generator<sizeof...(Args)>::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 <int... S>
R CallMethod(sequence<S...>) const {
return (object_->*method_)(std::get<S>(args_)...);
}
MethodT method_;
ObjectT* object_;
typename std::tuple<typename std::remove_reference<Args>::type...> args_;
};
template <class FunctorT, class R, typename... Args> template <class FunctorT, class R, typename... Args>
class Functor { class Functor {
public: public:
@ -183,6 +227,24 @@ MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
args...); args...);
} }
template <class ObjectT, class R, typename... Args>
MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
FP_T(method),
const scoped_refptr<ObjectT>& object,
typename detail::identity<Args>::type... args) {
return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object.get(),
args...);
}
template <class ObjectT, class R, typename... Args>
UnretainedMethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
FP_T(method),
detail::UnretainedWrapper<ObjectT> object,
typename detail::identity<Args>::type... args) {
return UnretainedMethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(
method, object, args...);
}
#undef FP_T #undef FP_T
#define FP_T(x) R (ObjectT::*x)(Args...) const #define FP_T(x) R (ObjectT::*x)(Args...) const
@ -194,17 +256,13 @@ MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind(
return MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(method, object, return MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(method, object,
args...); args...);
} }
#undef FP_T
#define FP_T(x) R (ObjectT::*x)(Args...)
template <class ObjectT, class R, typename... Args> template <class ObjectT, class R, typename... Args>
MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind( UnretainedMethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind(
FP_T(method), FP_T(method),
const scoped_refptr<ObjectT>& object, detail::UnretainedWrapper<const ObjectT> object,
typename detail::identity<Args>::type... args) { typename detail::identity<Args>::type... args) {
return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object.get(), return UnretainedMethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(
args...); method, object, args...);
} }
#undef FP_T #undef FP_T

View File

@ -87,6 +87,8 @@ EXPECT_IS_CAPTURED_AS_PTR(double);
EXPECT_IS_CAPTURED_AS_PTR(A); EXPECT_IS_CAPTURED_AS_PTR(A);
EXPECT_IS_CAPTURED_AS_PTR(D); EXPECT_IS_CAPTURED_AS_PTR(D);
EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*); EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
EXPECT_IS_CAPTURED_AS_PTR(
decltype(Unretained<RefCountedObject<RefCountInterface>>));
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface); EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B); EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);