diff --git a/mfbt/RefPtr.h b/mfbt/RefPtr.h index 0b6fa60db273..3c9be7ff8af9 100644 --- a/mfbt/RefPtr.h +++ b/mfbt/RefPtr.h @@ -131,6 +131,8 @@ class RefPtr friend class TemporaryRef; friend class OutParamRef; + struct dontRef {}; + public: RefPtr() : ptr(0) { } RefPtr(const RefPtr& o) : ptr(ref(o.ptr)) {} @@ -164,13 +166,15 @@ public: TemporaryRef forget() { T* tmp = ptr; ptr = 0; - return TemporaryRef(tmp); + return TemporaryRef(tmp, dontRef()); } T* get() const { return ptr; } operator T*() const { return ptr; } T* operator->() const { return ptr; } T& operator*() const { return *ptr; } + template + operator TemporaryRef() { return forget(); } private: void assign(T* t) { @@ -206,7 +210,10 @@ class TemporaryRef // To allow it to construct TemporaryRef from a bare T* friend class RefPtr; + typedef typename RefPtr::dontRef dontRef; + public: + TemporaryRef(T* t) : ptr(RefPtr::ref(t)) {} TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} template @@ -221,7 +228,7 @@ public: } private: - TemporaryRef(T* t) : ptr(t) {} + TemporaryRef(T* t, const dontRef&) : ptr(t) {} mutable T* ptr; @@ -231,10 +238,13 @@ private: /** * OutParamRef is a wrapper that tracks a refcounted pointer passed as - * an outparam argument to a function. If OutParamRef holds a ref to - * an object that's reassigned during a function call in which the - * OutParamRef is an outparam, then the old object is unref'd and the - * new object is ref'd. + * an outparam argument to a function. OutParamRef implements COM T** + * outparam semantics: this requires the callee to AddRef() the T* + * returned through the T** outparam on behalf of the caller. This + * means the caller (through OutParamRef) must Release() the old + * object contained in the tracked RefPtr. It's OK if the callee + * returns the same T* passed to it through the T** outparam, as long + * as the callee obeys the COM discipline. * * Prefer returning TemporaryRef from functions over creating T** * outparams and passing OutParamRef to T**. Prefer RefPtr* @@ -246,7 +256,10 @@ class OutParamRef friend OutParamRef byRef(RefPtr&); public: - ~OutParamRef() { refPtr = tmp; } + ~OutParamRef() { + RefPtr::unref(refPtr.ptr); + refPtr.ptr = tmp; + } operator T**() { return &tmp; } @@ -260,6 +273,9 @@ private: OutParamRef& operator=(const OutParamRef&); }; +/** + * byRef cooperates with OutParamRef to implement COM outparam semantics. + */ template OutParamRef byRef(RefPtr& ptr) @@ -299,26 +315,29 @@ struct Bar : public Foo { }; TemporaryRef NewFoo() { - RefPtr f = new Foo(); - return f.forget(); + return RefPtr(new Foo()); } TemporaryRef NewBar() { - RefPtr b = new Bar(); - return b.forget(); + return new Bar(); } void GetNewFoo(Foo** f) { *f = new Bar(); + // Kids, don't try this at home + (*f)->AddRef(); } void GetPassedFoo(Foo** f) -{} +{ + // Kids, don't try this at home + (*f)->AddRef(); +} void GetNewFoo(RefPtr* f) @@ -330,6 +349,12 @@ void GetPassedFoo(RefPtr* f) {} +TemporaryRef +GetNullFoo() +{ + return 0; +} + int main(int argc, char** argv) { @@ -407,6 +432,12 @@ main(int argc, char** argv) } MOZ_ASSERT(13 == Foo::numDestroyed); + { + RefPtr f = GetNullFoo(); + MOZ_ASSERT(13 == Foo::numDestroyed); + } + MOZ_ASSERT(13 == Foo::numDestroyed); + return 0; }