ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
我们在external目录下建立一个C++应用程序weightpointer来说明强指针和弱指针的使用方法,它的目录结构如下: ~~~ ~/Android ----external ----weightpointer ----weightpointer.cpp ----Android.mk ~~~ 应用程序weightpointer的实现很简单,它只有一个源文件 weightpointer.cpp和一个编译脚本文件Android.mk。下面我们就分别介绍它们的内容。 **weightpointer.cpp** ~~~ #include <stdio.h> #include <utils/RefBase.h> #define INITIAL_STRONG_VALUE (1<<28) using namespace android; class WeightClass : public RefBase { public: void printRefCount() { int32_t strong = getStrongCount(); weakref_type* ref = getWeakRefs(); printf("-----------------------\n"); printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong)); printf("Weak Ref Count: %d.\n", ref->getWeakCount()); printf("-----------------------\n"); } }; class StrongClass : public WeightClass { public: StrongClass() { printf("Construct StrongClass Object.\n"); } virtual ~StrongClass() { printf("Destory StrongClass Object.\n"); } }; class WeakClass : public WeightClass { public: WeakClass() { extendObjectLifetime(OBJECT_LIFETIME_WEAK); printf("Construct WeakClass Object.\n"); } virtual ~WeakClass() { printf("Destory WeakClass Object.\n"); } }; class ForeverClass : public WeightClass { public: ForeverClass() { extendObjectLifetime(OBJECT_LIFETIME_FOREVER); printf("Construct ForeverClass Object.\n"); } virtual ~ForeverClass() { printf("Destory ForeverClass Object.\n"); } }; void TestStrongClass(StrongClass* pStrongClass) { wp<StrongClass> wpOut = pStrongClass; pStrongClass->printRefCount(); { sp<StrongClass> spInner = pStrongClass; pStrongClass->printRefCount(); } sp<StrongClass> spOut = wpOut.promote(); printf("spOut: %p.\n", spOut.get()); } void TestWeakClass(WeakClass* pWeakClass) { wp<WeakClass> wpOut = pWeakClass; pWeakClass->printRefCount(); { sp<WeakClass> spInner = pWeakClass; pWeakClass->printRefCount(); } pWeakClass->printRefCount(); sp<WeakClass> spOut = wpOut.promote(); printf("spOut: %p.\n", spOut.get()); } void TestForeverClass(ForeverClass* pForeverClass) { wp<ForeverClass> wpOut = pForeverClass; pForeverClass->printRefCount(); { sp<ForeverClass> spInner = pForeverClass; pForeverClass->printRefCount(); } } int main(int argc, char** argv) { printf("Test Strong Class: \n"); StrongClass* pStrongClass = new StrongClass(); TestStrongClass(pStrongClass); printf("\nTest Weak Class: \n"); WeakClass* pWeakClass = new WeakClass(); TestWeakClass(pWeakClass); printf("\nTest Forever Class: \n"); ForeverClass* pForeverClass = new ForeverClass(); TestForeverClass(pForeverClass); pForeverClass->printRefCount(); delete pForeverClass; return 0; } ~~~ 文件首先定义了一个继承了RefBase类的WeightClass类,它只有一个成员函数printRefCount,用来打印对象的引用计数,包括强引用计数和弱引用计数。 然后又定义了三个类StrongClass、WeakClass和ForeverClass,它们都继承了WeightClass类。其中,StrongClass类对象的生命周期只受强引用计数影响,WeakClass类对象的生命周期同时受到强引用计数和弱引用计数的影响,ForeverClass类对象的生命周期完全不受强引用计数和弱引用计数的影响。 接着又定义了三个测试函数TestStrongClass、TestWeakClass和TestForeverClass,它们分别用来测试强指针和弱指针的三种使用情景,以验证我们对强指针和弱指针的实现原理分析。在TestStrongClass函数中,第70行将一个StrongClass对象赋值给一个弱指针wpOut,因此,第71行打印出该StrongClass对象的强引用计数值和弱引用计数值应该分别为0和1。接下来第74行再将该StrongClass对象赋值给一个强指针spInner,因此,第75行打印出该StrongClass对象的强引用计数值和弱引用计数值应该分别为1和2。函数执行到第78行时,由于已经超出了强指针spInner的作用域,因此,此时该StrongClass对象的强引用计数值和弱引用计数值应该分别为0和1。由于该StrongClass对象的生命周期只受强引用计数的影响,因此,该StrongClass对象会自动被释放,这一点可以通过观察StrongClass类的析构函数中的日志输出来确认。函数第78行试图将弱指针wpOut升级为强指针,但是由于弱指针wpOut所引用的StrongClass对象已经被释放,因此,弱指针wpOut升级为强指针就会失败,即第79行获得的强指针spOut所引用的对象地址就为0。当TestStrongClass函数返回时,由于超出了弱指针wpOut的作用域,因此,此时该StrongClass对象的弱引用计数值也会减少为0。 在TestWeakClass函数中,第84行将一个WeakClass对象赋值给一个弱指针wpOut,因此,第85行打印出该WeakClass对象的强引用计数值和弱引用计数值应该分别为0和1。接下来第88行再将该WeakClass对象赋值给一个强指针spInner,因此,第89行打印出该WeakClass对象的强引用计数值和弱引用计数值应该分别为1和2。函数执行到第92行时,由于已经超出了强指针spInner的作用域,因此,此时该WeakClass对象的强引用计数值和弱引用计数值应该为0和1。由于该WeakClass对象的生命周期同时受强引用计数和弱引用计数的影响,因此,此时该WeakClass对象不会被释放。函数第93行试图将弱指针wpOut升级为强指针,由于弱指针wpOut所引用的WeakClass对象还存在,因此,弱指针wpOut就能够成功升级为强指针spOut,即第94行获得的强指针spOut所引用的对象地址就不为0,并且此时该WeakClass对象的强引用计数值和弱引用计数值应该分别为1和2。当TestWeakClass函数返回时,由于超出了弱指针wpOut和强指针spOut的作用域,因此,此时该WeakClass对象的强引用计数值和弱引用计数值都应该减少为0,于是它就会被释放,这一点可以通过观察WeakClass类的析构函数中的日志输出来确认。 在TestForeverClass函数中,第99行将一个ForeverClass对象赋值给一个弱指针wpOut,因此,第100行打印出该ForeverClass对象的强引用计数值和弱引用计数值应该分别为0和1。接下来第103行再将该ForeverClass对象赋值给一个强指针spInner,因此,第104行打印出该ForeverClass对象的强引用计数值和弱引用计数值应该分别为1和2。当TestForeverClass函数返回时,由于超出了弱指针wpOut和强指针spInner的作用域,因此,此时该ForeverClass对象的强引用计数值和弱引用计数值都应该减少为0。但是由于该ForeverClass对象的生命周期不受强引用计数和弱引用计数的影响,因此它不会被自动释放,这一点可以通过观察WeakClass类的析构函数有没有日志输出来确认。 最后,在应用程序weightpointer的入口函数main中,分别调用了上述三个测试函数来验证强指针和弱指针的实现原理。由于第111行和第115行创建的对象都受到引用计数的影响,因此,它们会被自动释放;而第119行创建的对象不受引用计数的影响,因此,我们需要在第122行中手动地释放该对象。 **Android.mk** ~~~ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := weightpointer LOCAL_SRC_FILES := weightpointer.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils include $(BUILD_EXECUTABLE) ~~~ 这是应用程序weightpointer的编译脚本文件,它引用了libcutils和libutils两个库。 上述两个文件准备好之后,我们就可以对这个C++工程进行编译和打包了。 ~~~ USER@MACHINE:~/Android$ mmm ./external/weightpointer/ USER@MACHINE:~/Android$ make snod ~~~ 编译成功之后,就可以在out/target/product/gerneric/system/bin目录下看到应用程序文件weightpointer了;打包成功之后,该应用程序就包含在out/target/product/gerneric目录下的Android系统镜像文件system.img中了。 最后,我们使用新得到的系统镜像文件system.img来启动Android模拟器。Android模拟器启动起来之后,使用adb工具连接上它,并进入到/system/bin目录中,运行应用程序weightpointer来查看它的输出,从而验证强指针和弱指针的实现原理。 ~~~ USER@MACHINE: ~/Android$ emulator & USER@MACHINE:~/Android$ adb shell root@android:/ # cd system/bin/ root@android:/system/bin # ./weightpointer Test Strong Class: Construct StrongClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- Destory StrongClass Object. spOut: 0x0. Test Weak Class: Construct WeakClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- spOut: 0xa528. Destory WeakClass Object. Test Forever Class: Construct ForeverClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- ----------------------- Strong Ref Count: 0. Weak Ref Count: 0. ----------------------- Destory ForeverClass Object. ~~~ 如果能看到上面的输出,就说明我们前面对强指针和弱指针的实现原理的分析是正确的。