一 STL的智能指針及使用
STL中智能指針有std::shared_ptr std::weak_ptr std::unique_ptr std::auto_ptr僻爽。其中auto_ptr在C++11時已經(jīng)被啟用,C++17刪除了蔗衡。
其中std::shared_ptr 與android 的強(qiáng)指針sp用法相似,而std::weak_ptr 與android中的wp用法相似逼纸。相關(guān)用法如下例用例
// OLD, problem with dangling pointer
// PROBLEM: ref will point to undefined data!
int* ptr = new int(10);
int* ref = ptr;
delete ptr;
// NEW
// SOLUTION: check expired() or lock() to determine if pointer is valid
// empty definition
std::shared_ptr<int> sptr;
// takes ownership of pointer
sptr.reset(new int);
*sptr = 10;
// get pointer to data without taking ownership
std::weak_ptr<int> weak1 = sptr;
// deletes managed object, acquires new pointer
sptr.reset(new int);
*sptr = 5;
// get pointer to new data without taking ownership
std::weak_ptr<int> weak2 = sptr;
// weak1 is expired!
if(auto tmp = weak1.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak1 is expired\n";
// weak2 points to new data (5)
if(auto tmp = weak2.lock())
std::cout << *tmp << '\n';
else
std::cout << "weak2 is expired\n";
unique_ptr和shared_ptr的區(qū)別是济蝉,unique_ptr 不能copy。
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr
二 android的智能指針
android使用自己的智能指針sp和wp贺嫂,沒有使用STL的智能指針雁乡。
在使用強(qiáng)弱指針前類要繼承RefBase。
sp和wp之間的相互轉(zhuǎn)化也比較簡單曲饱。
sp<Foo> sp1(foo);
wp<Foo> wp1(sp1);
sp<Bar> sp1 = wpBuffer.promote();
三 STL和android的智能指針比較
總結(jié)下來珠月,主要的區(qū)別是
1 android的智能指針需要繼承RefBase方能使用,而STL則需要額外分配智能指針的分配空間驻谆。
2 由于是繼承庆聘,android 的sp和wp可以采用編譯檢查機(jī)制。
std::weak_ptr<int> gw;
void observe()
{
std::cout << "use_count == " << gw.use_count() << ": ";
if (auto spt = gw.lock()) { // Has to be copied into a shared_ptr before usage
std::cout << *spt << "\n";
}
else {
std::cout << "gw is expired\n";
}
}
int main()
{
{
auto sp = std::make_shared<int>(42);
gw = sp;
observe();
}
observe();
}
如果weak_ptr要轉(zhuǎn)為shared_ptr需要使用Lock函數(shù)
// weak_ptr::operator= example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp1,sp2;
std::weak_ptr<int> wp;
// sharing group:
// --------------
sp1 = std::make_shared<int> (10); // sp1
wp = sp1; // sp1, wp
sp2 = wp.lock(); // sp1, wp, sp2
sp1.reset(); // wp, sp2
sp1 = wp.lock(); // sp1, wp, sp2
std::cout << "*sp1: " << *sp1 << '\n';
std::cout << "*sp2: " << *sp2 << '\n';
return 0;
}
網(wǎng)上相關(guān)的解答比較少区端,比較有說服力的如下:
It automatically allows you to create sp from any object implementing RefBase, while for shared pointer you can shoot yourself in the foot while trying to wrap raw pointer into shared one.
So while for shared_ptr you might need this: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
for sp you can almost safely pass raw pointer to sp contructor.
總結(jié)起來就是android的智能指針使用可以針對任何繼承RefBase的類。比如前面的例子:
Foo* foo = new Foo(&isDeleted);
sp<Foo> sp1(foo);
而如果你用STL的智能指針時
#include <memory>
#include <iostream>
struct Good: std::enable_shared_from_this<Good> // note: public inheritance
{
std::shared_ptr<Good> getptr() {
return shared_from_this();
}
};
struct Bad
{
std::shared_ptr<Bad> getptr() {
return std::shared_ptr<Bad>(this);
}
~Bad() { std::cout << "Bad::~Bad() called\n"; }
};
int main()
{
// Good: the two shared_ptr's share the same object
std::shared_ptr<Good> gp1 = std::make_shared<Good>();
std::shared_ptr<Good> gp2 = gp1->getptr();
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';
// Bad: shared_from_this is called without having std::shared_ptr owning the caller
try {
Good not_so_good;
std::shared_ptr<Good> gp1 = not_so_good.getptr();
} catch(std::bad_weak_ptr& e) {
// undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17)
std::cout << e.what() << '\n';
}
// Bad, each shared_ptr thinks it's the only owner of the object
std::shared_ptr<Bad> bp1 = std::make_shared<Bad>();
std::shared_ptr<Bad> bp2 = bp1->getptr();
std::cout << "bp2.use_count() = " << bp2.use_count() << '\n';
} // UB: double-delete of Bad
輸出結(jié)果
gp2.use_count() = 2
bad_weak_ptr
bp2.use_count() = 1
Bad::~Bad() called
Bad::~Bad() called
*** glibc detected *** ./test: double free or corruption
必須要使用enable_shared_from_this 酱塔,解釋如下:
Publicly inheriting from std::enable_shared_from_this<T> provides the type T with a member function shared_from_this. If an object t of type T is managed by a std::shared_ptr<T> named pt, then calling T::shared_from_this will return a new std::shared_ptr<T> that shares ownership of t with pt.
這就驗證了前面的一個回答
It saves a memory allocation. When you write:
std::shared_ptr<Foo> pFoo{new Foo(bar)};
pFoo actually has a pointer to a shared data structure (allocated on the heap), which has the reference counters, and the pointer to the actual Foo object. By making objects be derived from RefBase, you can embed the reference counts in the object itself (saving the additional memory allocation).
Interestingly, with C++11 onwards, you can avoid the additional memory allocation by using std::make_shared<Foo> which will do a single memory allocation and construct the shared data structure and the Foo object in it.
The fact there is no compile time checking of the derivation from RefBase is carelessness. m_ptr should have been declared as RefBase *m_ptr, and then operator * (etc) should have done a static_cast to T*. In fact, I would probably have made sp<T> inherit from sp_base which had the comparison operators as public, and the other functions as protected.
Edit
On second thoughts, there is quite a bit of compile time checking. If T doesn't have an incStrong member, the compilation will fail, and it almost certainly won't unless it derives from RefBase. I still think converting a T* to a RefBase* would have been a better check, but the one that is there is probably good enough.