淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr。本站提示廣大學習愛好者:(淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr正文
一. scoped_ptr
boost::scoped_ptr和std::auto_ptr異常相似,是一個簡略的智能指針,它可以或許包管在分開感化域後對象被主動釋放。以下代碼演示了該指針的根本運用:
#include <string>
#include <iostream>
#include <boost/scoped_ptr.hpp>
class implementation
{
public:
~implementation() { std::cout <<"destroying implementation\n"; }
void do_something() { std::cout << "did something\n"; }
};
void test()
{
boost::scoped_ptr<implementation> impl(new implementation());
impl->do_something();
}
void main()
{
std::cout<<"Test Begin ... \n";
test();
std::cout<<"Test End.\n";
}
該代碼的輸入成果是:
Test Begin ...
did something
destroying implementation
Test End.
可以看到:當implementation類離其開impl感化域的時刻,會被主動刪除,如許就會防止因為忘卻手動挪用delete而形成內存洩露了。
boost::scoped_ptr特色:
boost::scoped_ptr的完成和std::auto_ptr異常相似,都是應用了一個棧上的對象去治理一個堆上的對象,從而使得堆上的對象跟著棧上的對象燒毀時主動刪除。分歧的是,boost::scoped_ptr有著更嚴厲的應用限制——不克不及拷貝。這就意味著:boost::scoped_ptr指針是不克不及轉換其一切權的。
1.不克不及轉換一切權
boost::scoped_ptr所治理的對象性命周期僅僅局限於一個區間(該指針地點的"{}"之間),沒法傳到區間以外,這就意味著boost::scoped_ptr對象是不克不及作為函數的前往值的(std::auto_ptr可以)。
2.不克不及同享一切權
這點和std::auto_ptr相似。這個特色一方面使得該指針簡略易用。另外一方面也形成了功效的軟弱——不克不及用於stl的容器中。
3.不克不及用於治理數組對象
因為boost::scoped_ptr是經由過程delete來刪除所治理對象的,而數組對象必需經由過程deletep[]來刪除,是以boost::scoped_ptr是不克不及治理數組對象的,假如要治理數組對象須要應用boost::scoped_array類。
boost::scoped_ptr的經常使用操作:
可以簡化為以下情勢:
namespace boost {
template<typename T> class scoped_ptr : noncopyable {
public:
explicit scoped_ptr(T* p = 0);
~scoped_ptr();
void reset(T* p = 0);
T& operator*() const;
T* operator->() const;
T* get() const;
void swap(scoped_ptr& b);
};
template<typename T>
void swap(scoped_ptr<T> & a, scoped_ptr<T> & b);
}
它的經常使用操作以下:
成員函數
功效
operator*()
以援用的情勢拜訪所治理的對象的成員
operator->()
以指針的情勢拜訪所治理的對象的成員
get()
釋放所治理的對象,治理別的一個對象
swap(scoped_ptr& b)
交流兩個boost::scoped_ptr治理的對象
#include <boost/scoped_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/config.hpp>
#include <boost/detail/lightweight_test.hpp>
void test()
{
// test scoped_ptr with a built-in type
long * lp = new long;
boost::scoped_ptr<long> sp ( lp );
BOOST_TEST( sp.get() == lp );
BOOST_TEST( lp == sp.get() );
BOOST_TEST( &*sp == lp );
*sp = 1234568901L;
BOOST_TEST( *sp == 1234568901L );
BOOST_TEST( *lp == 1234568901L );
long * lp2 = new long;
boost::scoped_ptr<long> sp2 ( lp2 );
sp.swap(sp2);
BOOST_TEST( sp.get() == lp2 );
BOOST_TEST( sp2.get() == lp );
sp.reset(NULL);
BOOST_TEST( sp.get() == NULL );
}
void main()
{
test();
}
boost::scoped_ptr和std::auto_ptr的拔取:
boost::scoped_ptr和std::auto_ptr的功效和操作都異常相似,若何在他們之間拔取取決因而否須要轉移所治理的對象的一切權(如能否須要作為函數的前往值)。假如沒有這個須要的話,年夜可使用boost::scoped_ptr,讓編譯器來停止更嚴厲的檢討,來發明一些不准確的賦值操作。
二. shared_ptr
boost::scoped_ptr固然簡略易用,但它不克不及同享一切權的特征卻年夜年夜限制了其應用規模,而boost::shared_ptr可以處理這一局限。望文生義,boost::shared_ptr是可以同享一切權的智能指針,起首讓我們經由過程一個例子看看它的根本用法:
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
class implementation
{
public:
~implementation() { std::cout <<"destroying implementation\n"; }
void do_something() { std::cout << "did something\n"; }
};
void test()
{
boost::shared_ptr<implementation> sp1(new implementation());
std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n";
boost::shared_ptr<implementation> sp2 = sp1;
std::cout<<"The Sample now has "<<sp2.use_count()<<" references\n";
sp1.reset();
std::cout<<"After Reset sp1. The Sample now has "<<sp2.use_count()<<" references\n";
sp2.reset();
std::cout<<"After Reset sp2.\n";
}
void main()
{
test();
}
該法式的輸入成果以下:
The Sample now has 1 references
The Sample now has 2 references
After Reset sp1. The Sample now has 1 references
destroying implementation
After Reset sp2.
可以看到,boost::shared_ptr指針sp1和sp2同時具有了implementation對象的拜訪權限,且當sp1和sp2都釋放對該對象的一切權時,其所治理的的對象的內存才被主動釋放。在同享對象的拜訪權限同時,也完成了其內存的主動治理。
boost::shared_ptr的內存治理機制:
boost::shared_ptr的治理機制其實其實不龐雜,就是對所治理的對象停止了援用計數,當新增一個boost::shared_ptr對該對象停止治理時,就將該對象的援用計數加一;削減一個boost::shared_ptr對該對象停止治理時,就將該對象的援用計數減一,假如該對象的援用計數為0的時刻,解釋沒有任何指針對其治理,才挪用delete釋放其所占的內存。
下面的誰人例子可以的圖示以下:
1.sp1對implementation對象停止治理,其援用計數為1
2.增長sp2對implementation對象停止治理,其援用計數增長為2
3.sp1釋放對implementation對象停止治理,其援用計數變成1
4.sp2釋放對implementation對象停止治理,其援用計數變成0,該對象被主動刪除
boost::shared_ptr的特色:
和後面引見的boost::scoped_ptr比擬,boost::shared_ptr可以同享對象的一切權,是以其應用規模根本上沒有甚麼限制(照樣有一些須要遵守的應用規矩,下文中引見),天然也能夠應用在stl的容器中。別的它照樣線程平安的,這點在多線程法式中也異常主要。
boost::shared_ptr的應用規矩:
boost::shared_ptr其實不是相對平安,上面幾條規矩能使我們加倍平安的應用boost::shared_ptr:
1.防止對shared_ptr所治理的對象的直接內存治理操作,以避免形成該對象的重釋放
2.shared_ptr其實不能對輪回援用的對象內存主動治理(這點是其它各類援用計數治理內存方法的通病)。
3.不要結構一個暫時的shared_ptr作為函數的參數。
以下列代碼則能夠招致內存洩露:
void test()
{
foo(boost::shared_ptr<implementation>(new implementation()),g());
}
准確的用法為:
void test()
{
boost::shared_ptr<implementation> sp (new implementation());
foo(sp,g());
}
三. weak_ptr
輪回援用:
援用計數是一種方便的內存治理機制,但它有一個很年夜的缺陷,那就是不克不及治理輪回援用的對象。一個簡略的例子以下:
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
class parent;
class children;
typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<children> children_ptr;
class parent
{
public:
~parent() { std::cout <<"destroying parent\n"; }
public:
children_ptr children;
};
class children
{
public:
~children() { std::cout <<"destroying children\n"; }
public:
parent_ptr parent;
};
void test()
{
parent_ptr father(new parent());
children_ptr son(new children);
father->children = son;
son->parent = father;
}
void main()
{
std::cout<<"begin test...\n";
test();
std::cout<<"end test.\n";
}
運轉該法式可以看到,即便加入了test函數後,因為parent和children對象相互援用,它們的援用計數都是1,不克不及主動釋放,而且此時這兩個對象再沒法拜訪到。這就惹起了c++中那污名昭著的內存洩露。
普通來說,消除這類輪回援用有上面有三種可行的辦法:
1.當只剩下最初一個援用的時刻須要手動打破輪回援用釋放對象。
2.當parent的生計期跨越children的生計期的時刻,children改成應用一個通俗指針指向parent。
3.應用弱援用的智能指針打破這類輪回援用。
固然這三種辦法都可行,但辦法1和辦法2都須要法式員手動掌握,費事且輕易失足。這裡重要引見一下第三種辦法和boost中的弱援用的智能指針boost::weak_ptr。
強援用和弱援用
一個強援用當被援用的對象在世的話,這個援用也存在(就是說,當至多有一個強援用,那末這個對象就不克不及被釋放)。boost::share_ptr就是強援用。
絕對而言,弱援用當援用的對象在世的時刻紛歧定存在。僅僅是當它存在的時刻的一個援用。弱援用其實不修正該對象的援用計數,這意味這弱援用它其實不對對象的內存停止治理,在功效上相似於通俗指針,但是一個比擬年夜的差別是,弱援用能檢測到所治理的對象能否曾經被釋放,從而防止拜訪不法內存。
boost::weak_ptr
boost::weak_ptr<T>是boost供給的一個弱援用的智能指針,它的聲明可以簡化以下:
namespace boost {
template<typename T> class weak_ptr {
public:
template <typename Y>
weak_ptr(const shared_ptr<Y>& r);
weak_ptr(const weak_ptr& r);
~weak_ptr();
T* get() const;
bool expired() const;
shared_ptr<T> lock() const;
};
}
可以看到,boost::weak_ptr必需從一個boost::share_ptr或另外一個boost::weak_ptr轉換而來,這也解釋,停止該對象的內存治理的是誰人強援用的boost::share_ptr。boost::weak_ptr只是供給了對治理對象的一個拜訪手腕。
boost::weak_ptr除對所治理對象的根本拜訪功效(經由過程get()函數)外,還有兩個經常使用的功效函數:expired()用於檢測所治理的對象能否曾經釋放;lock()用於獲得所治理的對象的強援用指針。
經由過程boost::weak_ptr來打破輪回援用
因為弱援用不更改援用計數,相似通俗指針,只需把輪回援用的一方應用弱援用,便可消除輪回援用。關於下面的誰人例子來講,只需把children的界說改成以下方法,便可消除輪回援用:
class children
{
public:
~children() { std::cout <<"destroying children\n"; }
public:
boost::weak_ptr<parent> parent;
};
最初值得一提的是,固然經由過程弱援用指針可以有用的消除輪回援用,但這類方法必需在法式員能預感會湧現輪回援用的情形下能力應用,也能夠是說這個僅僅是一種編譯期的處理計劃,假如法式在運轉進程中湧現了輪回援用,照樣會形成內存洩露的。是以,不要以為只需應用了智能指針便能根絕內存洩露。究竟,關於C++來講,因為沒有渣滓收受接管機制,內存洩露對每個法式員來講都是一個異常頭痛的成績。