Android 智能指针(3):终篇

上篇:Android 智能指针(1):hello world 篇

中篇:Android 智能指针(2):RefBase 核心篇

为什么是最后一篇?wp还没有写,就结局了?Android 智能指针源码,可读性相对较高,看完RefBase之后,其他的操作便是一目了然...

一:引子shared_from_this

C++ 为了避免对象计数混乱和double free,引入模板enable_shared_from_this.

class TestObject{
public:
~TestObject(){
std::cout<<"~TestObject Destructor"<<std::endl;
}
std::shared_ptr<TestObject> getObjectsp(){
std::cout<<"TestObject getObjectsp"<<std::endl;
return std::shared_ptr<TestObject>(this);
}
};
void testNormalSP() {
shared_ptr<TestObject> ptr = make_shared<TestObject>();
auto ptr2 = ptr->getObjectsp();
std::cout<<"count: "<<ptr.use_count()<<std::endl;
}
TestObject getObjectsp
count: 1
~TestObject Destructor
double free or corruption (out)
Aborted (core dumped)

所以c++里的对象如果想用智能指针来管理,直接继承enable_shared_from_this,来解决这个问题:

class TestObject:public std::enable_shared_from_this<TestObject>{
public:
~TestObject(){
std::cout<<"~TestObject Destructor"<<std::endl;
}
std::shared_ptr<TestObject> getObjectsp(){
std::cout<<"TestObject getObjectsp"<<std::endl;
//return std::shared_ptr<TestObject>(this);
return shared_from_this();
}
};
TestObject getObjectsp
count: 2
~TestObject Destructor

同样的操作,放到android里看下:

class TestObject2:public RefBase{
public:
~TestObject2(){
std::cout<<"~TestObject2 Destructor"<<std::endl;
}
sp<TestObject2> getObjectsp(){
std::cout<<"TestObject2 getObjectsp"<<std::endl;
return sp<TestObject2>(this);
}
};

void testGetspFromObject(){
TestObject2 *raw= new TestObject2();
sp<TestObject2> ptr(raw);
sp<TestObject2> ptr2=ptr->getObjectsp();
std::cout<<"android sp count: "<<ptr2->getStrongCount()<<std::endl;
}

int main() {
testGetspFromObject();
cout<<"main exit...\n";
return 0;
}
TestObject2 getObjectsp
android sp count: 2
~TestObject2 Destructor
main exit..

nice,Android 智能指针没有double free... 吃个安心丸子... 小结:Android智能指针,object 可以由“多个”智能指针来管理。

当然这是表面上的,得双引号,且看源码:

template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
if (other) {
other->incStrong(this);
}
}

说到底还是,让对象自身去管理应用计数,计数不是智能指针来负责管理。上篇RefBase也已经说明。

这个点上,Android智能指针用的很巧妙,一条龙服务,彻底解决引用计数问题。如果你想使用智能指针,那么就必须要继承RefBase,你只要继承了就解决了,即使其他人维护或修改你的代码,也不存在计数问题。C++的对象如果万一被其他人加个接口,直接通过this创建一个shared_ptr指针返回。又或者,直接发生一个对象指针赋值给了2个智能指针。这些潜在的风险在Android智能指针这里都不会发生。

二, wp弱指针

都写到这里了,还是要提下弱指针。弱指针定义放在了RefBase.h,没有单独的文件,服务sp,也是指针中的牛马~

template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}
//createWeak 会call 调用incWeak 增加引用计数
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
const int32_t c __unused = impl->mWeak.fetch_add(1,
std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

// promotion to sp

sp<T> promote() const;

弱指针使用前需要通过这个promote转成sp.

这里要注意:

void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
//skip
refs->mBase->onFirstRef();
}

这里是强指针增加计数的地方,这里同时也会给incWeak加计数。

std::atomic<int32_t> mWeak;

所以,RefBase 里的 weak计数,是所有引用的总和。 存在即合理的哲学下,wp也有它闪光的地方。 在事件,通知服务类型业务中,就能很好体现他的价值。

三,wp 用例

所有的测试代码上传到gitee gitee.com/git2cheng/p…

最后为了体现wp的价值,模拟客户去商店订购水果。大致实现"缺货-订货-补货-销售"流程。

角色:
Customer: 顾客,可以购买商品
MarketVendor: 供应商,负责补充商品库存
TransferService: 交易服务,协调顾客和供应商之间的交互
事务:
顾客请求购买商品,如果商店(mStore)没有库存.将顾客需求加入等待队列(mClientQueue)通知供应商补货.
供应商收到通知后,会送来10件商品,补货后检查等待队列,满足顾客需求.

除了使用智能指针(sp/wp)管理对象生命周期,也用了多线程模拟异步操作。

以下是头文件:

struct Customer : public RefBase
{
std::string mName;
wp<TransferService> mService;
//skip...
};

struct Event
{
//skip...
std::string mData;
wp<Customer> mCustomer;
};

struct MarketVendor : public RefBase
{
wp<TransferService> mService;

void setService(const sp<TransferService> &service) { mService = service; }
void onReceiveOrder(const std::string &product);
void deliverProducts(const std::string &product);
};

struct TransferService : public RefBase
{
std::vector<wp<Customer>> mClients;
wp<MarketVendor> mMarketVendor;
//skip...
};

//商店检查库存
bool TransferService::checkAndDeliverFromStore(const sp<Customer> &customer, const std::string &product)
{
std::lock_guard<std::mutex> lock(mStoreMutex);

auto it = std::find_if(mStore.begin(), mStore.end(),
[&product](const ProductInfo &info)
{ return info.name == product; });

if (it != mStore.end() && it->count > 0)
{
it->count--;
customer->onReceiveProduct(product, 1);

if (it->count == 0)
{
mStore.erase(it);
}
std::cout << product << " left: " << it->count << std::endl;
return true;
}
else
{
std::cout << product << " is out of stock,to order from vendor " << std::endl;
}
return false;
}

这里都是弱指针保存远端对象。

运行的结果:

Apple is out of stock,to order from vendor
Vendor received order for Apple
Apple is out of stock,to order from vendor
Vendor received order for Apple
Banana is out of stock,to order from vendor
Vendor received order for Banana
Orange is out of stock,to order from vendor
Vendor received order for Orange
Customer ZhangSan received 1 Apple
Apple left: 9
Customer Lisi received 1 Apple
Apple left: 8
Customer ZhangSan received 1 Banana
Banana left: 9
Customer Lisi received 1 Orange
Orange left: 9

工程里的lib就是从Android 开源库里裁剪解耦下来的指针库,放在了aarch64 上编译。

三,总结

终篇主要总结了 Android 智能指针和 C++ 通用指针在计数维护方面的差异。Android 智能指针从设计上便避免了多个智能指针管理同一个原始指针的风险。此外,在 Android 中,sp和wp配合使用,能够在各种复杂的业务场景里防止对象资源的泄漏. 最后需要再次强调,RefBase乃是Android 指针的灵魂...

 上篇:Android 智能指针(1):hello world 篇

中篇:Android 智能指针(2):RefBase 核心篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值