Hi folks,
I'm still a bit confused on which types (nsCOMPtr, ...) to use when
exactly, in combination w/ IDLs.
Let's consider a case where an nsArray is created and returned
(as rval, not out-parameter):
IDL:
[scriptable, uuid(ea0d8b3d-a549-4666-82d8-3a82cee2a3f1)]
interface nsIAddrBookService : nsISupports
{
nsIArray FindRecipients(in AString name);
...
}
C++:
/* nsIArray FindRecipients (in AString name); */
NS_IMETHODIMP nsAddrBookService::FindRecipients(const nsAString & addr,
nsIArray * *_retval)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> list =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
*_retval = list;
return FillRecipients(addr, list);
}
I'd assume that do_CreateInstance() returns the object w/ refcnt=1.
The assignment to nsCOMPtr should increase refcount. Correct ?
When the function is left, the nsCOMPtr is destroyed, and refcnt
goes back to 1 (we now have a reference left in the caller's pointer
field).
Now the caller side: (inspired by various examples ...)
nsCOMPtr<nsIArray> list;
rv = addrBookService->FindRecipients(
splittedRecipients[j].mEmail,
getter_AddRefs(list));
I'd guess getter_AddRefs() causes refcnt to be increased again, so
we're back at 2. That could lead to a leak, when that function returns
(and doesn't pass the ref anywhere else).
So, should I use dont_AddRef() here ?
Is the situation different when using out parameter instead of rval ?
BTW: what happens when passing nsCOMPtr as a reference (w/o IDL) ?
Assume the following code:
void caller() {
nsCOMPtr<nsIFoo> ref;
callee(ref);
ref->Something();
}
void callee(nsCOMPtr & outref) {
nsCOMPtr<nsIFoo> myref = do_CreateInstance(...);
...
outref = myref;
}
I'd assume that the last line will fill the caller's ref field w/ the
pointer and increase the object's refcnt (so it's 2 now), then when
callee is left, its myref is destroyed and refcnt is back to 1.
Is that correct ?
--mtx
Hello Enrico,
sadly our tech people don't have time for individual training sessions
via e-mail. There are plenty of correct code examples and that
ref-counting stuff is also documented:
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Using_nsCOMPtr
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Using_nsCOMPtr/Reference_Manual
The principle isn't hard to grasp, the object basically counts its
references and when the last one goes away, the object can be destroyed.
You can even print the reference count (mRefCnt) at any time you like.
You seem to have trouble understanding what a callee should do, so just
look at some, just picking one at random:
On 16/08/2017 12:56, Enrico Weigelt, metux IT consult wrote:
I'd assume that do_CreateInstance() returns the object w/ refcnt=1.
No. The assignment to the nsCOMPtr causes a ref-count of 1. At the end
of the function, the pointer is destroyed, the ref-count drops to 0 and
the referenced object can also be destroyed.
void caller() {
nsCOMPtr<nsIFoo> ref;
callee(ref);
That is already non-standard since you'd use getter_AddRefs()
ref->Something();
}
void callee(nsCOMPtr & outref) {
Again, non-standard, use nsIFoo** here.
nsCOMPtr<nsIFoo> myref = do_CreateInstance(...);
...
outref = myref;
Again, non-standard, you'd use NS_ADDREF(*outref = myref) here.
When the function exits, the object is left with one reference, since
the reference from myref dies and the one you added remains. In the
caller that reference dies when the caller exits.
Jörg.
On 8/16/2017 3:56 AM, Enrico Weigelt, metux IT consult via Maildev wrote:
Hi folks,
I'm still a bit confused on which types (nsCOMPtr, ...) to use when
exactly, in combination w/ IDLs.
As a general rule, if you are going to access a component using the
methods in the idl, then you should use an nsCOMPtr. Only if you want to
create a component and use non-idl methods on it, you should use nsRefPtr.
Let's consider a case where an nsArray is created and returned
(as rval, not out-parameter):
IDL:
[scriptable, uuid(ea0d8b3d-a549-4666-82d8-3a82cee2a3f1)]
interface nsIAddrBookService : nsISupports
{
nsIArray FindRecipients(in AString name);
...
}
C++:
/* nsIArray FindRecipients (in AString name); */
NS_IMETHODIMP nsAddrBookService::FindRecipients(const nsAString &
addr, nsIArray * *_retval)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> list =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
*_retval = list;
return FillRecipients(addr, list);
}
The typical pattern here would be to use .forget, see for example the
current code for NS_IMETHODIMP
nsAbManager::GetUserProfileDirectory(nsIFile **userDir). The returned
_retval needs to have an addref, which gets transferred from the local
to the return value with .forget Your example does not do the addref, so
would not be acceptable.
I'd assume that do_CreateInstance() returns the object w/ refcnt=1.
The assignment to nsCOMPtr should increase refcount. Correct ?
When the function is left, the nsCOMPtr is destroyed, and refcnt
goes back to 1 (we now have a reference left in the caller's pointer
field).
Now the caller side: (inspired by various examples ...)
nsCOMPtr<nsIArray> list;
rv = addrBookService->FindRecipients(
splittedRecipients[j].mEmail,
getter_AddRefs(list));
I'd guess getter_AddRefs() causes refcnt to be increased again, so
we're back at 2.
No, the pattern is that a getter is expected to return a ptr that has
addref done already (by the .forget in my example). "getter_AddRefs"
says that the gitter has already done the addref, so that the local
nsCOMPtr does not need to do it again.
So, should I use dont_AddRef() here ?
I have never used a dont_AddRef, and it should not typically be done in
routine idl component access.
Is the situation different when using out parameter instead of rval ?
Not in C++.
BTW: what happens when passing nsCOMPtr as a reference (w/o IDL) ?
Assume the following code:
void caller() {
nsCOMPtr<nsIFoo> ref;
callee(ref);
ref->Something();
}
callee(ref) is not a getter, so callee does no addref. But in your
example you have never assigned a value to ref, so you are passing a
null ptr, and this would crash at ref->Something().
void callee(nsCOMPtr & outref) {
nsCOMPtr<nsIFoo> myref = do_CreateInstance(...);
...
outref = myref;
}
Oh I see. We do not routinely use references for nsCOMPtr types, and I
do not know how it would react in this case. So I would reject this code
with an odd pattern in a review, and would need a very good explanation
of why this pattern was required before I would accept it.
:rkent
You should use |forget| to transfer the ownership of the nsIArray from list
to _retval.
/* nsIArray FindRecipients (in AString name); */
NS_IMETHODIMP nsAddrBookService::FindRecipients(const nsAString & addr,
nsIArray * *_retval)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> list =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv = FillRecipients(addr, list)) {
return rv;
}
list.forget(_retval);
return NS_OK;
}
On Wed, Aug 16, 2017 at 6:56 PM, Enrico Weigelt, metux IT consult <
enrico.weigelt@gr13.net> wrote:
Hi folks,
I'm still a bit confused on which types (nsCOMPtr, ...) to use when
exactly, in combination w/ IDLs.
Let's consider a case where an nsArray is created and returned
(as rval, not out-parameter):
IDL:
[scriptable, uuid(ea0d8b3d-a549-4666-82d8-3a82cee2a3f1)]
interface nsIAddrBookService : nsISupports
{
nsIArray FindRecipients(in AString name);
...
}
C++:
/* nsIArray FindRecipients (in AString name); */
NS_IMETHODIMP nsAddrBookService::FindRecipients(const nsAString & addr,
nsIArray * *_retval)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> list =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
*_retval = list;
return FillRecipients(addr, list);
}
I'd assume that do_CreateInstance() returns the object w/ refcnt=1.
The assignment to nsCOMPtr should increase refcount. Correct ?
When the function is left, the nsCOMPtr is destroyed, and refcnt
goes back to 1 (we now have a reference left in the caller's pointer
field).
Now the caller side: (inspired by various examples ...)
nsCOMPtr<nsIArray> list;
rv = addrBookService->FindRecipients(
splittedRecipients[j].mEmail,
getter_AddRefs(list));
I'd guess getter_AddRefs() causes refcnt to be increased again, so
we're back at 2. That could lead to a leak, when that function returns
(and doesn't pass the ref anywhere else).
So, should I use dont_AddRef() here ?
Is the situation different when using out parameter instead of rval ?
BTW: what happens when passing nsCOMPtr as a reference (w/o IDL) ?
Assume the following code:
void caller() {
nsCOMPtr<nsIFoo> ref;
callee(ref);
ref->Something();
}
void callee(nsCOMPtr & outref) {
nsCOMPtr<nsIFoo> myref = do_CreateInstance(...);
...
outref = myref;
}
I'd assume that the last line will fill the caller's ref field w/ the
pointer and increase the object's refcnt (so it's 2 now), then when
callee is left, its myref is destroyed and refcnt is back to 1.
Is that correct ?
--mtx
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform
On 17.08.2017 04:03, Shih-Chiang Chien wrote:
You should use |forget| to transfer the ownership of the nsIArray from
list to _retval.
Ok, thanks. Already suspected that (found some similar things in the
code). Could we update the docs (maybe some set of examples) ?
IIRC, there're some places that do it like in my prev mail, which I took
as example (just forget where exactly that was) - should that be fixed ?
By the way: is there a difference between out parameters and rval ?
Or can I just assume, rval's are equivalent to an out parameter ?
OTOH, is there a way to create versions that really return it as rval,
so I conveniently could just call like that ?
nsCOMPtr<nsIMutableArray> list = addrbook->FindRecipients(addr);
--mtx
On Thu, Aug 17, 2017 at 7:07 AM, Enrico Weigelt, metux IT consult
enrico.weigelt@gr13.net wrote:
OTOH, is there a way to create versions that really return it as rval,
so I conveniently could just call like that ?
nsCOMPtr<nsIMutableArray> list = addrbook->FindRecipients(addr);
You can do this with a return type of
already_AddRefed<nsIMutableArray>. Then instead of
list.forget(_retval);
return NS_OK;
you do just
return list.forget();
Note that in this case you cannot ignore the return value -- it must
be assigned to an nsCOMPtr or a RefPtr, or else it will leak. Ideally
we would allow a return type of nsCOMPtr<nsIMutableArray>&&, but
currently I think we don't.