Reputation: 529
I cannot figure out the following difference in Android framework (in C++) as
class foo {
...
}
class child_foo : public foo {
...
}
sp<child_foo> item = new child_foo;
const sp<foo> &r1 = item;
Then the strong count of item is 2.
However, if it is in
sp<child_foo> item = new child_foo;
const sp<child_foo> &r1 = item;
Then the strong count of item is 1.
What's the difference between them?
I also noticed that const sp<foo> &r2 = item;
will invoke sp's(original typo of foo's) constructor, why?
Fix here, NOT foo's constructor but sp's (strong pointer's).
Thanks in advance!
Upvotes: 3
Views: 4121
Reputation: 15334
A sp<foo>
reference cannot bind directly to a sp<child_foo>
as it is a different type. But the compiler can construct a temporary sp<foo>
from a sp<child_foo>
to make the conversion. And because a const reference can prolong the lifetime of a temporary this temporary can then bind to the const reference. The strong count is then 2 because there are two sp
, item
and the temporary.
In the second case the const reference can bind directly to the sp<child_foo>
as they are the same type and no temporary is created and the strong count stays at 1.
Upvotes: 3
Reputation: 529
I want to add some comments here.
I am interested in this problem because there seems that a lot of place where it appears.
Sorry at first since U need to fix my description.
I also noticed that const sp &r2 = item; will invoke sp's constructor, why?
The invoked constructor is as below.
https://android.googlesource.com/platform/frameworks/native/+/jb-dev/include/utils/StrongPointer.h
template<typename T> template<typename U>
sp<T>::sp(U* other) : m_ptr(other)
{
if (other) ((T*)other)->incStrong(this);
}
There are a lot places this logic appears by, ex:
status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) {
...
mLooper->registerHandler(this);
...
}
Then check registerHandler of ALooper.cpp https://android.googlesource.com/platform/frameworks/av/+/7296123/media/libstagefright/foundation/ALooper.cpp
ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
return gLooperRoster.registerHandler(this, handler);
}
The pass by reference makes the same effect as
const sp<foo> &r1 = item;
to increase reference count by 1.
Finally,
gLooperRoster.registerHandler(this, handler)
ALooper::handler_id ALooperRoster::registerHandler(
const sp<ALooper> looper, const sp<AHandler> &handler) {
Mutex::Autolock autoLock(mLock);
if (handler->id() != 0) {
CHECK(!"A handler must only be registered once.");
return INVALID_OPERATION;
}
HandlerInfo info;
info.mLooper = looper;
info.mHandler = handler;
ALooper::handler_id handlerID = mNextHandlerID++;
mHandlers.add(handlerID, info);
handler->setID(handlerID);
return handlerID;
}
At this time, the second pass by reference will NOT increase the reference count.
To clarify it, I emulate the inheritance layer since MediaCodec inherits AHandler. Therefore the first call is as assigning child's pointer to reference type of strong pointer which is template by parent's type.
If you are interested in it, you can give it a try.
Thanks.
Upvotes: 0