【问题标题】:smart pointer (Android strong pointer) reference type copy智能指针(Android强指针)引用类型拷贝
【发布时间】: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 对象并且引用计数增加了,那就很奇怪了。

标签: android c++ pointers smart-pointers


【解决方案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。因此,第一次调用是将子指针分配给强指针的引用类型,强指针是父类型的模板。

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

    谢谢。

    【讨论】:

      猜你喜欢
      • 2010-12-28
      • 1970-01-01
      • 2015-07-21
      • 2011-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      相关资源
      最近更新 更多