智能指针(Android强指针)引用类型拷贝

Posted

技术标签:

【中文标题】智能指针(Android强指针)引用类型拷贝【英文标题】:smart pointer (Android strong pointer) reference type copy 【发布时间】:2017-08-11 09:20:50 【问题描述】:

我无法弄清楚 android 框架(在 C++ 中)的以下区别

class foo 
  ... 

class child_foo : public foo 
  ...
 

sp<child_foo> item = new child_foo;
const sp<foo> &r1 = item;

那么item的强计数是2。

但是,如果它在

sp<child_foo> item = new child_foo;
const sp<child_foo> &r1 = item;

那么item的强计数是1。

它们有什么区别?

我还注意到const sp&lt;foo&gt; &amp;r2 = item; 会调用 sp's(original typo of foo's) 构造函数,为什么?

在这里修复,不是 foo 的构造函数,而是 sp(强指针)。

提前致谢!

【问题讨论】:

对智能指针的引用不会增加智能指针的引用计数。您只需为智能指针创建一个别名(第二个示例)。不确定为什么调用 foo 的构造函数。我猜你在这里混淆了,因为如果在第一个例子中创建了一个新的 foo 对象并且引用计数增加了,那就很奇怪了。 【参考方案1】:

sp&lt;foo&gt; 引用不能直接绑定到 sp&lt;child_foo&gt;,因为它是不同的类型。但是编译器可以从sp&lt;child_foo&gt; 构造一个临时的sp&lt;foo&gt; 来进行转换。并且因为 const 引用可以延长临时的生命周期,所以这个临时可以绑定到 const 引用。强计数为 2,因为有两个 spitem 和临时的。

在第二种情况下,const 引用可以直接绑定到sp&lt;child_foo&gt;,因为它们是相同的类型,并且没有创建临时值,并且强计数保持在 1。

【讨论】:

【参考方案2】:

我想在这里添加一些 cmets。

我对这个问题很感兴趣,因为它出现的地方似乎很多。

首先很抱歉,因为你需要修正我的描述。

我还注意到 const sp &r2 = item;将调用 sp 的 构造函数,为什么?

调用的构造函数如下。

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);

这个逻辑出现在很多地方,例如:

status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) 
     ...
     mLooper->registerHandler(this);
     ...

然后查看ALooper.cpp的registerHandler 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);

引用传递的效果和

一样
const sp<foo> &r1 = item;

将引用计数增加 1。

最后,

gLooperRoster.registerHandler(this, handler)

其实调用 https://android.googlesource.com/platform/frameworks/av/+/b6f7642496f955da04d1eb9e33df0dab653c9c4e/media/libstagefright/foundation/ALooperRoster.cpp

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;
 

此时,第二次通过引用不会增加引用计数。

为了澄清这一点,我模拟了继承层,因为 MediaCodec 继承了 AHandler。因此,第一次调用是将子指针分配给强指针的引用类型,强指针是父类型的模板。

如果你对它感兴趣,可以试试看。

谢谢。

【讨论】:

以上是关于智能指针(Android强指针)引用类型拷贝的主要内容,如果未能解决你的问题,请参考以下文章

探索android系统中的强指针实现

探索android系统中的强指针实现

复合类型——引用和指针

C++原生指针,引用与智能指针

第22课 weak_ptr弱引用智能指针

智能指针 与 oc中的指针