Closed
Bug 178187
Opened 22 years ago
Closed 13 years ago
|nsCOMPtr|: better named functions for using |already_AddRefed| with raw pointers
Categories
(Core :: XPCOM, enhancement)
Core
XPCOM
Tracking
()
RESOLVED
WONTFIX
People
(Reporter: scc, Unassigned)
References
Details
see bug #172030 for a complete discussion, but I will abstract here:
When a function returns an |already_AddRefed| and the caller intends to manage
that result in a raw pointer, the current notation is unclear, and may be
confusing to people who have formed a specific mental model about the meaning of
|.get()| from other classes
T* t = f().get()
...does not make clear the transfer of ownership (though please note,
|already_AddRefed| is an annotation, not a manager of ownership). Maybe
|already_AddRefed<T>::get()| needs a new name. Maybe we need a new external
helper function. I currently favor a name like |accept_ownership_of|:
T* t = accept_ownership_of( f() );
Note: the use of raw pointers in this position is actively discouraged. The use
is expected to be rare. Therefor, the more explicit the naming the better, and
also this bug is probably of significantly lower priority.
Reporter | ||
Updated•22 years ago
|
Blocks: nsCOMPtr_tracking
Comment 1•22 years ago
|
||
Just as a note... I've been going through the tree looking for functions that
return raw addrefed pointers. About 50-60% of the callers of such functions are
actually assigning the result directly into an out param. So if we were to
start converting functions returning addrefed pointers to returning
already_AddRefed (a not-too-small "if") we would be hard=pressed to discourage
the use (unless we demand that people use an intermediate nsCOMPtr with the
ensuing AddRef/Release).
I agree that the annotation should be very explicit in such cases; I'm just not
sure I agree that this is very low priority. ;)
Reporter | ||
Updated•22 years ago
|
Status: NEW → ASSIGNED
Reporter | ||
Comment 3•22 years ago
|
||
Here's one possible way to add this machinery. In this scheme, we go to a
little trouble to prevent accidents in cases like
already_AddRefed<T> CreateAFoo();
// this is the right way to assign into an |nsCOMPtr|
nsCOMPtr<T> t = CreateAFoo();
// but with the scheme below, this works too
nsCOMPtr<T> t = accept_ownership_of( CreateAFoo() );
nsCOMPtr<T> t = CreateAFoo().get();
Note that with the curent implementation of |already_AddRefed::get()|, this last
statement would be a leak.
// add this new class
template <class T>
struct unsafe_already_AddRefed
{
unsafe_already_AddRefed( T* aRawPtr )
: mRawPtr(aRawPtr)
{
// nothing else to do here
}
operator T*() const { return mRawPtr; }
// this is the operation that makes
// this class `unsafe', it automatically
// converts to a raw pointer on demand
// throwing away the extra type information
T* mRawPtr;
};
// change this existing class (in the |get| member)
template <class T>
struct already_AddRefed
{
already_AddRefed( T* aRawPtr )
: mRawPtr(aRawPtr)
{
// nothing else to do here
}
unsafe_already_AddRefed<T>
get() const
{
return unsafe_already_AddRefed<T>(mRawPtr);
}
T* mRawPtr;
};
// this is the whole point, adding this utility
template <class T>
inline
const unsafe_already_AddRefed<T>
accept_ownership_of( const already_AddRefed<T>& aAlreadyAddRefedPtr )
{
return aAlreadyAddRefedPtr.get();
}
// add some more signatures of existing functions for the
// new `unsafe' class
template <class T>
inline
const already_AddRefed<T>
getter_AddRefs( const unsafe_already_AddRefed<T>& aAlreadyAddRefedPtr )
{
return already_AddRefed<T>(aAlreadyAddRefedPtr);
}
template <class T>
inline
const already_AddRefed<T>
dont_AddRef( const unsafe_already_AddRefed<T>& aAlreadyAddRefedPtr )
{
return already_AddRefed<T>(aAlreadyAddRefedPtr);
}
template <class T>
inline
void
do_QueryInterface( const unsafe_already_AddRefed<T>& )
{
// This signature exists... blah, blah,
// as per the other dummy |do_QueryInterface| implementations
}
template <class T>
inline
void
do_QueryInterface( const unsafe_already_AddRefed<T>&, nsresult* )
{
// This signature exists... blah, blah,
// as per the other dummy |do_QueryInterface| implementations
}
// a couple of additions to |nsCOMPtr| itself
template <class T>
inline
nsCOMPtr<T>::nsCOMPtr( const unsafe_already_AddRefed<T>& aSmartPtr )
: NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
{
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
template <class T>
inline
nsCOMPtr<T>&
nsCOMPtr<T>::operator=( const unsafe_already_AddRefed<T>& rhs )
{
assign_assuming_AddRef(rhs.mRawPtr);
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
// ...and similarly for |nsCOMPtr<nsISupports>|
Reporter | ||
Comment 4•22 years ago
|
||
Not sure I like the above solution. I don't like the idea of adding yet another
support class. I definitely would want to examine generated code to see how the
compilers deal with this. You can see how this could quite easily suck in
practice, or, on the other hand, be completely optimized out of the generated
code. Also, on some broken compilers, I would expect assignment into an
|nsCOMPtr| to be ambiguous trying to choose between the unconverted class, and
assignment from the automatically converted raw pointer. This also needs to be
tested.
Updated•18 years ago
|
Assignee: scc → nobody
Status: ASSIGNED → NEW
QA Contact: scc → xpcom
Comment 5•13 years ago
|
||
forget/swap to the rescue
Status: NEW → RESOLVED
Closed: 13 years ago
Resolution: --- → WONTFIX
You need to log in
before you can comment on or make changes to this bug.
Description
•