程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr

淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr

編輯:關於C++

淺析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 <string>
#include <iostream>

#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++來講,因為沒有渣滓收受接管機制,內存洩露對每個法式員來講都是一個異常頭痛的成績。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved