• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            alex

            alex

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              7 隨筆 :: 6 文章 :: 7 評(píng)論 :: 0 Trackbacks

            2007年2月11日 #

            今天來(lái)講講怎么編寫異常安全的代碼。
            程序運(yùn)行過(guò)程中,往往需要對(duì)一些流程加入異常處理,來(lái)提高程序的robust.比如
            通過(guò)try catch來(lái)捕捉異常
            try
            {
            ??? pMemory = new char[MAX_BUF_SIZE];
            }
            catch(std::bad_alloc& e)
            {
            ??? //error handling,er:do something resource free
            }
            但在程序代碼段中出現(xiàn)大量的try catch,不僅從美觀,效率和程序輸寫上都是不怎么好。
            而另外一種對(duì)于異常的處理方法是依賴于c++的ctor/dctor的匹配來(lái)做的,就是所謂的
            RAII,這個(gè)很容易讓人聯(lián)想到std::auto_ptr
            std::auto_ptr<int> tmp(new int);
            通過(guò)new分配的對(duì)象會(huì)在tmp生命結(jié)束后,釋放相關(guān)的資源,通過(guò)這種方式,就能保證在程序異常,或退出時(shí),已分配的對(duì)象能正確自動(dòng)的釋放擁有的資源,而在對(duì)象聲明周期內(nèi),可以保證資源的有效性。
            這種方式就是今天blog要寫的主要內(nèi)容,我們可以看到std::auto_ptr作用范圍很小,只能對(duì)從堆上分配的對(duì)象進(jìn)行管理,假如對(duì)文件打開(kāi)句柄實(shí)行RAII,你也許會(huì)認(rèn)為再寫個(gè)不就是了,但這樣只會(huì)造成源代碼里充滿了這些資源管理的類,這導(dǎo)致了一個(gè)嚴(yán)重的問(wèn)題,好的結(jié)構(gòu)在繁瑣的流暢前面變的難堪。
            那怎么樣對(duì)這個(gè)進(jìn)行泛化,從而能對(duì)比如從簡(jiǎn)單的指針釋放,文件句柄維護(hù),甚至相關(guān)的成員函數(shù)。我們來(lái)看下loki::socpeguard是怎么實(shí)現(xiàn)的:
            先看下基本的用法
            (1)? FILE* hFileOpen = fopen(....);
            (2)? LOKI_ON_BLOCK_EXIT(flose,hFileOpen);
            line2會(huì)在出LOKI_ON_BLOCK_EXIT域或程序異常結(jié)束時(shí)被調(diào)用,下面是對(duì)類成員的調(diào)用
            void CTestObject::Create
            {
            ??? LOKI_ON_BLOCK_EXIT_OBJ(*this,FressResouce);
            ??? ...
            }
            同上面差不多,會(huì)在這個(gè)函數(shù)結(jié)束后或異常結(jié)束后調(diào)用類成員的FreeResource.在正常流程結(jié)束后,可以通過(guò)調(diào)用Dismiss來(lái)防止對(duì)FreeResouce的調(diào)用,即類似數(shù)據(jù)庫(kù)操作的commit操作。下面來(lái)分析下LOKI的實(shí)現(xiàn):
            從上面可以看到,RAII的是:
            1:構(gòu)造函數(shù)對(duì)資源的獲取
            2:稀構(gòu)函數(shù)對(duì)資源的釋放
            先來(lái)看下LoKi對(duì)上面那2個(gè)宏的定義
            #define LOKI_ON_BLOCK_EXIT????? Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeGuard

            #define LOKI_ON_BLOCK_EXIT_OBJ? Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Loki::MakeObjGuard
            上面的Loki::ScopeGuard是一個(gè)基類的別名
            typedef const ScopeGuardImplBase& ScopeGuard;
            而LOKI_ANONYMOUS_VARIABLE(scopeGuard)用來(lái)我們產(chǎn)生唯一的名字,有時(shí)假如需要調(diào)用Dismiss的話,則需要自己去實(shí)現(xiàn)宏定義的內(nèi)容,這樣才能通過(guò)對(duì)象訪問(wèn)。Loki::MakeGuard或Loki::MakeObjGuard是用來(lái)產(chǎn)生對(duì)象的實(shí)際類型的,下面是一個(gè)
            Loki::MakeGuard的例子:
            template <typename F, typename P1>
            inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
            {
            ??? return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
            }
            可以看到ScopeGuardImpl1<F, P1>是要產(chǎn)生的具體類型,MakeGuard通過(guò)函數(shù)參數(shù)的數(shù)目來(lái)重載的,而MakeGuard此處的作用是要睡死了...-_-'',作用是利用函數(shù)自動(dòng)推導(dǎo)出參數(shù)的類型,這樣就免去了指定ScopeGuardImpl1的類型的麻煩,而
            ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
            簡(jiǎn)單的返回對(duì)象的一個(gè)臨時(shí)變量,并assign給一個(gè)上面的一個(gè)scopeguard的實(shí)例,這里依賴一個(gè)C++的特性,臨時(shí)變量的聲命周期和通過(guò)他初始化的引用類型的聲明周期是一致的。

            從上面可以看到Loki定義了一個(gè)ScopeGuardImplBase的基礎(chǔ)類。這個(gè)類定義了一個(gè)基本的方法Dismiss,以及相關(guān)的狀態(tài)。下面是loki中這個(gè)類的定義
            class ScopeGuardImplBase
            {
            ??? ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
            ?protected:
            ??? ~ScopeGuardImplBase()
            ??? {}
            ??? ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
            ??????? : dismissed_(other.dismissed_)
            ??? {
            ??????? other.Dismiss();
            ??? }
            ??? template <typename J>
            ??? static void SafeExecute(J& j) throw()
            ??? {
            ??????? if (!j.dismissed_)
            ?????????? try
            ?????????? {
            ????????????? j.Execute();
            ?????????? }
            ?????????? catch(...)
            ?????????? {}
            ???? }
            ???????
            ???? mutable bool dismissed_;
            public:
            ???? ScopeGuardImplBase() throw() : dismissed_(false)
            ???? {}
            ???? void Dismiss() const throw()
            ???? {
            ???????? dismissed_ = true;
            ????? }
            };
            可以看到類里面定義了上面所說(shuō)的一些屬性,其中SafeExecute用來(lái)提供子類同一的資源釋放方法,并調(diào)用子類的方法來(lái)具體操作,因?yàn)橄嚓P(guān)的函數(shù),變量都保存在具體的子類,可以看到這個(gè)函數(shù)使用了try catch,這里加這個(gè)的目的是,因?yàn)橘Y源釋放要在子類的稀構(gòu)里被觸發(fā),而調(diào)用具體的方法是外面?zhèn)鬟M(jìn)來(lái)的,所以無(wú)法保證一定是異常安全的,而假如在稀構(gòu)里面異常的話,會(huì)導(dǎo)致程序的行為無(wú)法定義。
            下面具體來(lái)看下一個(gè)子類的實(shí)現(xiàn):
            template <typename F, typename P1>
            class ScopeGuardImpl1 : public ScopeGuardImplBase
            {
            public:
            ??? static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
            ??? {
            ??????? return ScopeGuardImpl1<F, P1>(fun, p1);
            ??? }
            ??? ~ScopeGuardImpl1() throw()
            ??? {
            ??????? SafeExecute(*this);
            ??? }
            ??? void Execute()
            ??? {
            ??????? fun_(p1_);
            ??? }
            protected:
            ??? ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
            ??? {}
            ??? F fun_;
            ??? const P1 p1_;
            };
            在LoKi里面可以看到很多類似ScopeGuardImpl1的定義,比如ScopeGuardImpl0,
            ScopeGuardImpl2,可以發(fā)現(xiàn)最后面的數(shù)字表示具體參數(shù)的數(shù)目。
            可以看到上面所說(shuō)的MakeGuard的定義,以及對(duì)基類方法的調(diào)用,可以看到構(gòu)造函數(shù)接收的類型,一個(gè)函數(shù)對(duì)象,和一些參數(shù)對(duì)象,并保存,對(duì)于成員函數(shù)的scopeguard,LoKi定義了1些相似的類,主要是增加了對(duì)象的引用,還有就是函數(shù)的調(diào)用方式上。
            上面可以看到參數(shù)是通過(guò)值的方式來(lái)保存的而不是通過(guò)引用。而且是const屬性的,下面是相關(guān)的分析。
            1:通過(guò)傳值的方式,從而避免了異常拋出時(shí),可能引用的對(duì)象被稀構(gòu)
            2:加const屬性,從而保證了在func需要參數(shù)是reference時(shí)而保存的參數(shù)確是非const時(shí)產(chǎn)生相應(yīng)的編譯錯(cuò)誤,因?yàn)閷?duì)reference傳人const non-reference形式是錯(cuò)誤的。
            而對(duì)于1的方式,存在的一種問(wèn)題是假如操作的fun需要傳入引用,那傳進(jìn)去的值就無(wú)法在釋放的函數(shù)中被改變,而2是對(duì)這種的一種類似契約似的編程,Loki 提供的方法是通過(guò)一個(gè)中間對(duì)象來(lái)保存操作參數(shù)的引用,并賦予這個(gè)對(duì)象自動(dòng)轉(zhuǎn)換功能。下面是這個(gè)類的定義:
            template <class T>
            class RefToValue
            {??
            public:
            ??? RefToValue(T& ref) : ref_(ref)
            ??? {}
            ??? RefToValue(const RefToValue& rhs) : ref_(rhs.ref_)
            ??? {}
            ??? operator T& () const
            ??? {
            ??????? return ref_;
            ??? }
            private:
            ??? // Disable - not implemented
            ??? RefToValue();
            ??? RefToValue& operator=(const RefToValue&);
            ???????
            ??? T& ref_;
            };
            可以很清楚的看到類的實(shí)現(xiàn),下面是一個(gè)工具類
            template <class T>
            inline RefToValue<T> ByRef(T& t)
            {
            ???? return RefToValue<T>(t);
            }
            下面給個(gè)具體的例子,假如
            template<typename _Ty>
            void SAFEDELETE(_Ty*& ptr)
            {
            ?? if (NULL != ptr)
            ????? delete ptr;
            ?? ptr = NULL;
            }

            char* ptr = new char;
            ?
            {
            ??? LOKI_ON_BLOCK_EXIT(SAFEDELETE<char>,Loki::ByRef(ptr));
            }
            ?
            if (NULL == ptr)
            ? std::cout << "NULL" << std::endl;
            基本上就這么多了,sleep去了
            ??????????????????????????????????????????????????? alex_yuu

            posted @ 2007-02-11 15:55 agerlis 閱讀(1379) | 評(píng)論 (3)編輯 收藏

            前幾天一個(gè)朋友給我看了1段代碼:
            any temp; //any is a class
            temp = 1;
            temp = "a";
            temp = x; //x is a abstract class

            看到這段代碼著實(shí)下了1跳.初期的感覺(jué)象void*指針那樣,又象variant變量。但感覺(jué)還是比較新穎的,-_-''也許我是菜鳥的原因,在腦袋轉(zhuǎn)了一下后,我實(shí)現(xiàn)了自己的一個(gè)類,用來(lái)接受任何參數(shù),起初我認(rèn)為any應(yīng)該是個(gè)typedef,而接收的類型也是前面知道的(-_-''又沒(méi)弄清需求就去實(shí)現(xiàn)了),所以實(shí)現(xiàn)一個(gè)接收任何參數(shù)的類需要個(gè)typelist,和對(duì)每種類型的泛化,下面是class的定義:

            template<typename _typelist>
            class?any
            {
            public:
            ?typedef typename Loki::TL::TypeAtNonStrict<_typelist,0>::Result?param1;
            ?typedef typename Loki::TL::TypeAtNonStrict<_typelist,1>::Result?param2;
            ?typedef typename Loki::TL::TypeAtNonStrict<_typelist,2>::Result?param3;
            ?typedef typename Loki::TL::TypeAtNonStrict<_typelist,3>::Result?param4;
            ?typedef typename Loki::TL::TypeAtNonStrict<_typelist,4>::Result?param5;

            ?any(param1 param):
            ??m_param1(param){}

            ?any(param2 param):
            ??m_param2(param){}

            ?any(param3 param):
            ??m_param3(param){}

            ?any(param4 param):
            ??m_param4(param){}

            ?template<typename _Ty>
            ?const _Ty&??Get()
            ?{
            ???? class?CERROR_ACCESS_DENIED;
            ???? LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -???? 1),CERROR_ACCESS_DENIED);

            ???? return?__Access<_Ty>();
            ?}
            private:
            ?template<typename _Ty>
            ?_Ty&? __Access();

            ?template<>
            ?param1& __Access<param1>() {return m_param1;}

            ?template<>
            ?param2& __Access<param2>() {return m_param2;}

            ?template<>
            ?param3& __Access<param3>() {return m_param3;}

            ?template<>
            ?param4& __Access<param4>() {return m_param4;}

            ?param1??m_param1;
            ?param2??m_param2;
            ?param3??m_param3;
            ?param4??m_param4;
            };

            typedef any<Loki::TYPE_LIST_3(int,float,char)>?ANY;

            這樣似乎就可以接收任何類型了,也可以取出數(shù)據(jù),取出時(shí)必須要知道相應(yīng)的類型,而且,假如類型不在列表里面,則編譯期出錯(cuò)
            class?CERROR_ACCESS_DENIED;
            LOKI_STATIC_CHECK((Loki::TL::IndexOf<_typelist,_Ty>::value != -???? 1),CERROR_ACCESS_DENIED);
            這樣,-_-''似乎就可以了,只要所接收的類型可以拷貝即可。但有個(gè)明了的缺陷,那1就是接收的類型必須編譯期寫死,假如不寫死的話,我個(gè)人開(kāi)始的認(rèn)為是加一個(gè)基類,-_-''
            還是要3q我那位朋友,讓我了解到boost::any的用法
            下面是boost::any的具體分析,我們要達(dá)到下面幾個(gè)要求:
            1:可以接收任何類型的數(shù)據(jù)(具有value屬性)
            2: 可以方便的取出數(shù)據(jù)
            3:型別安全,不象void*
            下面是boost::any的實(shí)現(xiàn),我按部分貼,而且省去我認(rèn)為不重要的東西,因?yàn)樘L(zhǎng)了,這會(huì)影響我blog的收視率。
            1:首先來(lái)看下他的構(gòu)造和稀構(gòu)(-_-''錯(cuò)別字)
            ?any()
            ????: content(0)
            {
            }
            ?
            ?template<typename ValueType>
            ?any(const ValueType & value)
            ????: content(new holder<ValueType>(value))
            {
            }
            ?
            any(const any & other)
            ????: content(other.content ? other.content->clone() : 0)
            ?{
            ?}
            ?
            ?~any()
            ?{
            ?????delete content;
            ?}
            從構(gòu)造函數(shù)可以看到,any可以接受默認(rèn)的,任何其他值包括ant本身,在稀構(gòu)里面可以看到對(duì)content的釋放,content在這里是一個(gè)基類的指針,是any內(nèi)部實(shí)現(xiàn)的,我們可以看到,在對(duì)any構(gòu)造是有種方法:
            (1)content(new holder<ValueType>(value))
            (2)content(other.content ? other.content->clone() : 0)
            稍后會(huì)看到holder是派生自content類型的一個(gè)模板實(shí)現(xiàn),也許講到這里,有些應(yīng)該明白了any是怎么保存任何類型的吧,對(duì)于其他any的構(gòu)造,我們發(fā)現(xiàn)調(diào)用了content的一個(gè)clone方法,很明顯這是content的一個(gè)虛方法,這個(gè)方法的存在得以讓我們運(yùn)用虛函數(shù)的機(jī)制正確的拷貝對(duì)象,下面會(huì)看到這只是個(gè)簡(jiǎn)單的new操作。
            2:來(lái)看下any的operator =的重載
            any & swap(any & rhs)
            {
            ?????std::swap(content, rhs.content);
            ?????return *this;
            }
            ?
            template<typename ValueType>
            any & operator=(const ValueType & rhs)
            {
            ????any(rhs).swap(*this);
            ????return *this;
            }
            ?
            any & operator=(const any & rhs)
            {
            ??????any(rhs).swap(*this);
            ??????return *this;
            }
            可以看到operator =,接收任何其他類型的參數(shù),swap方法的實(shí)現(xiàn),用來(lái)交換2個(gè)對(duì)象的content指針,我們可以看到operator =里面臨時(shí)對(duì)象的構(gòu)建,在函數(shù)結(jié)束后,自動(dòng)釋放原來(lái)content的對(duì)象,這有點(diǎn)RAII味道。(http://blog.sina.com.cn/u/1019039487)獨(dú)家小菜。。
            3:下面來(lái)看下輔助類
            ?bool empty() const
            ?{
            ??????return !content;
            ?}
            ?
            ?const std::type_info & type() const
            ?{
            ??????return content ? content->type() : typeid(void);
            ?}
            可以看到。一個(gè)empty,一個(gè)type,很形象。
            4:下面來(lái)看下上面content所指的對(duì)象,以及any怎么保存任何類型,以及這種怎么保證型別安全
            class placeholder
            {
            public: // structors
            ?????virtual ~placeholder()
            ?????{
            ?????}
            public: // queries
            ??????virtual const std::type_info & type() const = 0;
            ??????virtual placeholder * clone() const = 0;
            };
            ?
            template<typename ValueType>
            class holder : public placeholder
            {
            public: // structors
            ?????holder(const ValueType & value)
            ????????????? : held(value)
            ?????{
            ?????}
            public: // queries
            ?????virtual const std::type_info & type() const
            ?????{
            ?????????return typeid(ValueType);
            ?????}
            ?
            ?????virtual placeholder * clone() const
            ?????{
            ??????????return new holder(held);
            ?????}
            public: // representation
            ?????ValueType held;
            };(-_-''格式矯正真是類啊)
            ?
            placeholder就是上面content指向的對(duì)象,可以看到他定義的一些提供給any調(diào)用的函數(shù)和虛基本必須的虛稀構(gòu)函數(shù)(可以看到any對(duì)content調(diào)用了delete)
            下面是holder的實(shí)現(xiàn),holder是一個(gè)模板,里面定義的
            ValueType held;
            很明星是any用來(lái)保存任何類型的,回顧下上面所說(shuō)的any初始化content的2種方法
            (1)content(new holder<ValueType>(value))
            (2)content(other.content ? other.content->clone() : 0)
            從這個(gè)地方可以看到怎么初始化holder對(duì)象,并保存到content.注意到這里的held是public的,這樣就提供了對(duì)數(shù)據(jù)訪問(wèn)的功能,在訪問(wèn)的時(shí)候必須要知道具體要訪問(wèn)的類型,才能調(diào)用相應(yīng)的static_cast或者dynamic_cast來(lái)操作,而這樣其實(shí)也提供了型別安全的保證,eg:不象malloc,返回void*,然后()轉(zhuǎn)換一下。
            5:看下怎么訪問(wèn)any里面的屬性值:這里就不列舉出所有的實(shí)現(xiàn),因?yàn)橛行┦菍?duì)const的版本。
            template<typename ValueType>
            ValueType * any_cast(any * operand)
            {
            ????return operand && operand->type() == typeid(ValueType)
            ??????????????????? ? &static_cast<any::holder<ValueType> *>? (operand->content)->held
            ??????????????????? : 0;
            }
            ?
            template<typename ValueType>
            ValueType any_cast(const any & operand)
            {
            ?????typedef BOOST_DEDUCED_TYPENAME??????? remove_reference<ValueType>::type nonref;
            ?
            ???const nonref * result = any_cast<nonref>(&operand);
            ???if(!result)
            ??????????? boost::throw_exception(bad_any_cast());
            ????return *result;
            }//這里去掉1些原來(lái)實(shí)現(xiàn)的代碼和注釋
            可以看到具體的實(shí)現(xiàn)方式&dynamic_cast的邏輯差不多,對(duì)引用的cast有可能拋出異常。通過(guò)上面這種方式,就達(dá)到了對(duì)數(shù)據(jù)的讀取,讀取時(shí)必須知道里面的數(shù)據(jù)類型。可以看出any只能保存一個(gè)值,-_-''不向我那個(gè),可以同時(shí)保存不同類型的值。
            6:extension
            可以通過(guò)std::vector<boost::any> anys,來(lái)構(gòu)建一個(gè)任何類型的列表,但訪問(wèn)比較麻煩。
            也可以通過(guò)any來(lái)達(dá)到虛函數(shù)不能為template的限制(因?yàn)橐粋€(gè)是靜態(tài)的一個(gè)是動(dòng)態(tài)的)
            象下面:
            class CBase
            {
            ?public:
            ???? virtual void Set(boost::any) = 0;
            };
            ?
            class CHild:
            ???? public CBase
            {
            ?public:
            ???? virtual void Set(boost::any param)
            ???? {
            ????????? m_value = param;
            ???? }
            ?private:
            ???? boost::any? m_value;
            };
            ?
            CHild?test;
            CBase* ptr = &test;
            ptr->Set(1);
            ptr->Set('a');
            7.finish...總算完成了...-_-''要變唐僧了...
            ????????????????????????????????????????????????? alex. agerlis@163.com
            posted @ 2007-02-11 15:54 agerlis 閱讀(420) | 評(píng)論 (0)編輯 收藏

            聽(tīng)說(shuō)過(guò)一種時(shí)間管理的方法,是用來(lái)怎么安排任務(wù)和時(shí)間的,下面是大概的概念圖:
            ?

            ???????????????????????????????time - task

            圖中箭頭指向的方向表示緊迫度的添加,那么下面是關(guān)于1,2,3,4的定義:

            一:任務(wù)比較重要,但相應(yīng)的時(shí)間也很緊

            二:任務(wù)是長(zhǎng)期任務(wù),但比較重要

            三:不那么重要的任務(wù),時(shí)間也很多

            四:不需要多長(zhǎng)時(shí)間的非重要任務(wù)

            現(xiàn)在分析下上面的這些:
            對(duì)于一:往往這個(gè)時(shí)候處于時(shí)間的dead line狀態(tài),而此時(shí)往往是我們都不想要的,熟話說(shuō)事情是急不來(lái)的,這個(gè)時(shí)候往往會(huì)導(dǎo)致質(zhì)量的下降.

            對(duì)于二:我們有充足的時(shí)間來(lái)做重要的任務(wù),這正是我們想要的,但,怎么做才能使其不會(huì)過(guò)渡到區(qū)間一呢,轉(zhuǎn)為區(qū)間1往往會(huì)由于人的惰性產(chǎn)生的,關(guān)鍵是要提前做事.安排好時(shí)間.

            對(duì)于三:往往是一些可以輔助我們成長(zhǎng)的事情,這些東西對(duì)我們有益處,這對(duì)全面的發(fā)展起到了很好的作用,-_-''就象我學(xué)吉他..

            對(duì)于四:是些時(shí)間緊,但不重要的任務(wù),比如要幫助人去google一些資料.

            從上面可以看到,區(qū)間一實(shí)際上是最差的,但為了做好區(qū)間2,我們必須要盡量減少區(qū)間4的份量,而對(duì)于全面的發(fā)展,我們也要安排時(shí)間到區(qū)間3.這也是很重要的.

            posted @ 2007-02-11 15:54 agerlis 閱讀(352) | 評(píng)論 (0)編輯 收藏

            以前C讀取命令行參數(shù)感覺(jué)太麻煩,而且不容易記憶.下面是另外一種命令行的讀取方法
            通過(guò)GetCommandLine(),來(lái)返回當(dāng)前的命令行:
            setlocale(LC_ALL, ".ACP");
            std::wcout << GetCommandLine() << std::endl;
            下面是輸出:
            "e:\學(xué)習(xí)程序\consol3\debug\consol3.exe" a b c
            對(duì)于命令行的參數(shù)讀取用CommandLineToArgvW,可以把命令行參數(shù)轉(zhuǎn)換成字符串?dāng)?shù)組的形式
            int?nums = 0;
            TCHAR** temp = CommandLineToArgvW(GetCommandLine(),&nums);
            for(int i = 0; i < nums; i++)
            {
            ? std::wcout<< temp[i] << std::endl;
            }
            下面是輸出:
            e:\學(xué)習(xí)程序\consol3\debug\consol3.exe
            a
            b
            c

            可以看到命令行參數(shù)從下標(biāo)=1的元素開(kāi)始.
            感覺(jué)這種形式比較好記憶
            posted @ 2007-02-11 15:53 agerlis 閱讀(990) | 評(píng)論 (0)編輯 收藏

            abstract factory.感覺(jué)是個(gè)很玄的名字,即使在我寫學(xué)習(xí)筆記的時(shí)候,我也因?yàn)槿鄙佻F(xiàn)實(shí)中的實(shí)踐而對(duì)其了解不深。^^希望.... 多指正
            Name:
            ?? abstract factory
            Addressed Problem:
            ?? 提供對(duì)同1種相關(guān)對(duì)象的創(chuàng)建。比如在程序里面,希望根據(jù)用戶配置來(lái)設(shè)置UI方案,比如方案1和2,對(duì)應(yīng)的UI也存在2套不同的實(shí)現(xiàn)類,比如對(duì)于ScrollBar,有CScrollBar1和CScrollBar2,都繼承自ScrollBar。也許在程序里面有很多這樣的類。這樣你在應(yīng)用UI實(shí)例化類時(shí)就必須要選擇比如
            IScrollBar* pScrollBar = NULL;
            if (_use_ui_1)
            ?? pScrollBar = new CScrollBar1;
            else
            ?? pScrollBar = new CScrollBar2;
            也許你這樣感覺(jué)沒(méi)多大關(guān)系,但想象下,在程序的多處都存在這樣的選擇,為什么我不選擇一種less error phone的方法呢?比如
            pScrollBar = Create(...);
            這樣一種簡(jiǎn)單的方式呢?而且上面的寫法也引進(jìn)了1個(gè)避短,也就是在產(chǎn)生pScrollBar時(shí),涉及到了具體的實(shí)現(xiàn)類,這在面向?qū)ο筮@種program to interface這樣的語(yǔ)言中是很忌諱的事情。比如,在加種UI方案,也許你會(huì)再寫個(gè)else,這樣等于自己把自己往火堆里面推。你是一個(gè)勤奮的程序員,但不是個(gè)優(yōu)秀的程序員^^.也許有人會(huì)說(shuō),我可以利用prototype這樣的方式來(lái)啊。這樣,在程序的外面配置一下每個(gè)類的prototype就可以了,或許也可以用object factory啊,都可以(^^似乎是哦,我也沒(méi)學(xué)過(guò)這2個(gè)的說(shuō))解決上面的問(wèn)題,一個(gè)通過(guò)DoClone類似的,1個(gè)通過(guò)ID或其他的,其實(shí)在應(yīng)用上面的2種時(shí),自然的導(dǎo)出了abstract factory.為什么呢,因?yàn)樯厦娴?種,你都需要設(shè)置多個(gè)的原型或ID。比如也許在CUIManager的構(gòu)造里面寫賊大的if
            if (_use_ui_1)
            {
            ??? ...//設(shè)置UI_1下所有的prototype
            }
            else
            {
            ??? ...//設(shè)置UI_2下所有的prototype
            }
            也許在將來(lái)的莫天,在加上UI_3,則。再寫個(gè)if.也許大家可能會(huì)想,我在應(yīng)用ui時(shí),我就知道了所要?jiǎng)?chuàng)建的對(duì)象,為什么我不把上面寶裝一下改成:
            if (_use_ui_1)
            ?//設(shè)置factory_1
            else
            ?//設(shè)置factory_2
            然后在抽象出來(lái)的IFactory里面提供創(chuàng)建這些UI Class的方法,比如,CreateScrollBase.等等,這樣就有了abstract factory 的雛形。
            基礎(chǔ)實(shí)現(xiàn)
            /*
            ?測(cè)試abstract factory模式
            */

            class?IScrollWindow
            {
            public:
            ?virtual void?DrawScroll(void) = 0;
            };

            class?IListWindow
            {
            public:
            ?virtual?void?DrawList(void) = 0;
            };

            class?ICreateWindowFactory
            {
            public:
            ?virtual?IScrollWindow*?CreateScrollWindow(void) = 0;

            ?virtual?IListWindow*?CreateListWindow(void) = 0;
            };

            class?CBlueWindowFactory:
            ?public?ICreateWindowFactory
            {
            ?class?CBlueScrollWindow:
            ??public?IScrollWindow
            ?{
            ?public:
            ??virtual void?DrawScroll(void)
            ??{
            ???std::cout << "draw blue scroll" << std::endl;
            ??}
            ?};

            ?class?CBlueListWindow:
            ??public?IListWindow
            ?{
            ?public:
            ??virtual?void?DrawList(void)
            ??{
            ???std::cout << "draw blue list" << std::endl;
            ??}
            ?};
            public:
            ?virtual?IScrollWindow*?CreateScrollWindow(void)
            ?{
            ??return?new CBlueScrollWindow;
            ?}

            ?virtual?IListWindow*?CreateListWindow(void)
            ?{
            ??return?new CBlueListWindow;
            ?}
            };

            class?CRedWindowFactory:
            ?public?ICreateWindowFactory
            {
            ?class?CRedScrollWindow:
            ??public?IScrollWindow
            ?{
            ?public:
            ??virtual void?DrawScroll(void)
            ??{
            ???std::cout << "draw red scroll" << std::endl;
            ??}
            ?};

            ?class?CRedListWindow:
            ??public?IListWindow
            ?{
            ?public:
            ??virtual?void?DrawList(void)
            ??{
            ???std::cout << "draw red list" << std::endl;
            ??}
            ?};
            public:
            ?virtual?IScrollWindow*?CreateScrollWindow(void)
            ?{
            ??return?new CRedScrollWindow;
            ?}

            ?virtual?IListWindow*?CreateListWindow(void)
            ?{
            ??return?new CRedListWindow;
            ?}
            };
            在需要用的地方,就可以這樣:
            ICreateWindowFactory*?pCreateWindow1?= new CBlueWindowFactory;

            ?pCreateWindow1->CreateListWindow()->DrawList();
            ?pCreateWindow1->CreateScrollWindow()->DrawScroll();
            假如需要用不同的工廠,則更換不會(huì)影響到調(diào)用處的代碼。因?yàn)榈粲霉S的地方是面向接口的。其實(shí)abstract factory的理念應(yīng)該是比較簡(jiǎn)單的(^^瞎猜的).基本講完了什么是抽象類工廠,他要解決的一些問(wèn)題以及怎么解決和1個(gè)小而亂的demo代碼段。下面來(lái)看下我們?cè)趺捶夯@個(gè)類工廠,這個(gè)會(huì)涉及到loki里面的具體實(shí)現(xiàn),大家要加滿油啊,因?yàn)榉夯惞S是一件不容易的事情啊。

            泛化_1
            首先,(^^這部分我也不是很懂)要泛化的是abstract factory的接口,就象上面的CreateScrollWindow和CreateListWindow,在泛化時(shí)需要的信息是要?jiǎng)?chuàng)建的同1組對(duì)象的相關(guān)接口比如IScrollBar,IList等等,在loki里面,要為1個(gè)類泛化1組接口,可以通過(guò)GenScatterHierarchy來(lái)將unit應(yīng)用到typelist里的每1個(gè)類型,并將該類從unit<type>派生,從而得到1組接口。GenScatterHierarchy做了什么呢,他產(chǎn)生了啥呢?具體的可以看morden c++里面的實(shí)現(xiàn)。通過(guò)GenScatterHierarchy我們得到了我們要得1組接口。下面是loki里面對(duì)這個(gè)得相關(guān)實(shí)現(xiàn)
            template <class T>
            class AbstractFactoryUnit
            {
            public:
            ????virtual T* DoCreate(Type2Type<T>) = 0;
            ????virtual ~AbstractFactoryUnit() {}
            };

            可以看到,上面定義了2個(gè)函數(shù),而這個(gè)類就是我上面說(shuō)得調(diào)用GenScatterHierarchy時(shí),具現(xiàn)化時(shí)對(duì)typelist得每個(gè)類型應(yīng)用得template類,而最后產(chǎn)生得也將是類似AbstractFactoryUnit<IScrollBar>的類,我們具體的抽象工廠從這些派生。至于pure dctor這個(gè)大家應(yīng)該都知道啥作用。下面來(lái)看Abstract Factory 的泛化:

            template
            <
            ????class TList,
            ????template <class> class Unit = AbstractFactoryUnit
            >
            class AbstractFactory : public GenScatterHierarchy<TList, Unit>
            {
            public:
            ?????typedef TList ProductList;
            ???????
            ?????template <class T> T* Create()
            ?????{
            ????????Unit<T>& unit = *this;
            ????????return unit.DoCreate(Type2Type<T>());
            ?????}
            ?};
            可以看到這個(gè)即由GenScatterHierarchy來(lái)得到了我們想要的東西。提供了Create的模板函數(shù),使得我們可以象這樣factory.Create<IScrollBar>()的方便形勢(shì)來(lái)調(diào)用。ProductList是對(duì)于抽象工廠要?jiǎng)?chuàng)建的類型的重命名。方便后面在產(chǎn)生實(shí)際的類型時(shí),獲取對(duì)應(yīng)的類型信息,對(duì)于DoCreate的參數(shù),大家應(yīng)該都明白這是重載用的,那用在哪里呢?下面會(huì)介紹。

            泛化_2
            在辛苦介紹完泛化抽象工廠的接口后,我們可以通過(guò)類似的方式來(lái)定義1個(gè)abstract factory的接口
            Loki::AbstractFactory<LOKI_TYPELIST_2(IScrollBar,IListWindow)>
            下面我們來(lái)介紹最后的,我們?cè)趺磥?lái)提供抽象工廠的實(shí)現(xiàn),首先是對(duì)象的創(chuàng)建,loki里面提供了默認(rèn)的創(chuàng)建的方法,當(dāng)然我們可以修改或用特化的版本來(lái)做選擇。
            template <class ConcreteProduct, class Base>
            class OpNewFactoryUnit : public Base
            {
            ???? typedef typename Base::ProductList BaseProductList;
            ???
            protected:
            ?????typedef typename BaseProductList::Tail ProductList;
            ???
            public:
            ?????typedef typename BaseProductList::Head AbstractProduct;
            ?????ConcreteProduct* DoCreate(Type2Type<AbstractProduct>)
            ?????{
            ????????? return new ConcreteProduct;
            ?????}
            };
            可以看到DoCreate是我們的核心部分,里面調(diào)用了new來(lái)創(chuàng)建對(duì)象。而這里也讓我們看到這應(yīng)該是上面創(chuàng)建對(duì)象的重載。而Type2Type的作用正是在這里體現(xiàn)作用,因?yàn)閏++無(wú)法通過(guò)函數(shù)返回值來(lái)重載不同的對(duì)象。也許你會(huì)看到上面的一些類型定義,包括OpNewFactoryUnit的2個(gè)模板參數(shù),第2個(gè)模板參數(shù)是實(shí)現(xiàn)GenLinearHierarchy必備的GenLinearHierarchy和上面的GenScatterHierarchy的核心思想一樣,都是通過(guò)具現(xiàn)化來(lái)實(shí)現(xiàn)的,不過(guò)GenLinearHierarchy產(chǎn)生的是線性的繼承體系,中間夾雜著比如OpNewFactoryUnit<IScrollBar,GenLinearHierarchy<...> >這樣的形勢(shì)。下面來(lái)看下抽象工程的具體實(shí)現(xiàn)的泛化,聯(lián)系起來(lái)就能對(duì)上面的理解了
            template
            <
            ????class AbstractFact,
            ????template <class, class> class Creator = OpNewFactoryUnit,
            ????class TList = typename AbstractFact::ProductList
            >
            class ConcreteFactory
            ?????: public GenLinearHierarchy<
            ?????typename TL::Reverse<TList>::Result, Creator, AbstractFact>
            {
            public:
            ????typedef typename AbstractFact::ProductList ProductList;
            ????typedef TList ConcreteProductList;
            };
            可以看到ConcreteFactory由GenLinearHierarchy來(lái)驅(qū)動(dòng)產(chǎn)生我們想要的,本來(lái)這個(gè)貼圖比較明朗點(diǎn),但我懶的畫,哈哈。從GenLinearHierarchy的參數(shù)來(lái)看,第1個(gè)是具體的實(shí)現(xiàn)類的typelist,比如LOKI_TYPELIST2(CScrollBar_1,CListWindow_1),至于為什么要對(duì)類型做reverse操作,因?yàn)樵陬惖幕A(chǔ)體系產(chǎn)生后,typelist的第1個(gè)元素,在繼承體系是由下往上的,而于上面由OpNewFactoryUnit等定義的ProductList的Head定義的自上往下的是相反的,所以這里應(yīng)用了reverse操作。Creator就是上面的OpNewFactoryUnit或你自定義的元素。并在具現(xiàn)化是,應(yīng)用typelist的每個(gè)類型。AbstractFact是繼承體現(xiàn)的最頂端,這個(gè)應(yīng)該很明顯,就是上面定義的AbstractFactory,這樣啥都明確了,具體的接口,對(duì)接口的函數(shù)的重載都已經(jīng)泛化完成。下面是(^^睡死了,睡覺(jué)去了,簡(jiǎn)單從便,上面均未調(diào)試哦).至于為什么會(huì)把第3個(gè)參數(shù)默認(rèn)為抽象類工廠接口的ProductList,這個(gè)和loki用基于prototype的Creator有關(guān)系。。(^^俺是菜鳥,就只能到這里了)
            對(duì)abstract factory的看法,優(yōu)點(diǎn)在上面的已經(jīng)說(shuō)過(guò)了,確定在,我們要添加1種對(duì)象的創(chuàng)建時(shí),都要去修改接口的定義,當(dāng)然后面的泛化也為我們解決了些問(wèn)題,但泛化對(duì)于參數(shù)的傳遞不怎么好用,可以通過(guò)提供新的OpNewFactoryUnit來(lái)適當(dāng)解決。
            ??????????????????????????????????????????????????? agerlis.2007.2.10 0:22
            posted @ 2007-02-11 15:53 agerlis 閱讀(383) | 評(píng)論 (0)編輯 收藏

            handle-body,睡死了,但還是得堅(jiān)持下。其實(shí)這個(gè)是很簡(jiǎn)單的概念
            這個(gè)也稱呼為pimpl,是private implemention的縮寫,下面涉及到的都叫做pimpl, 那用這個(gè)到底有什么好處呢:
            1:可以把具體的實(shí)現(xiàn)從client端封裝,這樣即使修改實(shí)現(xiàn),只要不修改頭文件,對(duì)client端來(lái)說(shuō),是沒(méi)有任何影響的,甚至不改變代碼的2進(jìn)制特性
            2:加速編譯時(shí)間,我們知道有時(shí)頭文件有太多的實(shí)現(xiàn),會(huì)導(dǎo)致包含這個(gè)頭文件的其他文件的編譯時(shí)間增加,通過(guò)pimpl,我們把實(shí)現(xiàn)從頭文件移到cpp里面,從而減少了其他包含這個(gè)文件的編譯時(shí)間,加快編譯速度
            3:減少依賴,這個(gè)實(shí)際上也增加了編譯的速度,可以不對(duì)client端暴露一些實(shí)現(xiàn)上的頭文件,從而減少了依賴說(shuō)了這么多,下面來(lái)看下一個(gè)簡(jiǎn)單的pimpl的實(shí)現(xiàn)。是用loki的類來(lái)實(shí)現(xiàn)的。哈哈,睡死了,偷懶
            /*.h*/
            class CTest
            {
            public:
            ??? void Test();
            private:?
            ????Loki::PimplT::Type m_impl;
            };
            ------------------------------------------------------------------- /*.cpp*/
            template<>
            struct Loki::ImplT
            {
            public:
            ?? ?void Test() { std::cout << "test" << std::endl; }
            };

            void CTest::Test() { return m_impl->Test(); }

            上面只是個(gè)很簡(jiǎn)單很簡(jiǎn)單的例子,以至于有些還無(wú)法體會(huì)到pimpl的作用,但相信在實(shí)踐中你會(huì)體會(huì)到,把原來(lái)定義在CTest里面的一些私有的方法,成員,全部挪到ImplT里面時(shí),你會(huì)體會(huì)到,這個(gè)CTest的頭文件里include了很少的頭,他可以說(shuō)完成了原始的使命,達(dá)到了功能性接口的作用,而其他原來(lái)定義在頭里的.h,可以全部挪到cpp里了。下面來(lái)分析下loki是怎么實(shí)現(xiàn)的。可以看到實(shí)現(xiàn)pimpl首先需要牽置聲明pre define類,loki通過(guò)模板的全特化來(lái)實(shí)現(xiàn)了這個(gè)的隱藏,從而避免了把具體的實(shí)現(xiàn)類暴露給client的弊端。下面來(lái)看下這個(gè)泛化的pre define: template struct ImplT; 哈哈,很簡(jiǎn)單,再看上面我的cpp里的定義,大家結(jié)合上面也許就明白了吧,部過(guò),這里需要注意的是,CTest的構(gòu)造函數(shù)要寫后面,不然can;t compile. 但是,為什么具體的實(shí)現(xiàn)類是ImplT但,前面的
            Loki::PimplT::Type m_impl;
            那Loki::PimplT::Type是什么用的,我們知道,假如保存原始的
            Loki::ImplT<CTest>* m_impl;
            然后new一個(gè),其實(shí)這樣只存在1個(gè)問(wèn)題,2個(gè)不方便,
            1:?jiǎn)栴}是這樣的原始指針,不能傳播const信息,也就是說(shuō),對(duì)象CTest轉(zhuǎn)為const的化,他里面的指針類型不是同樣隨著帶有const屬性,也就是說(shuō),假如此時(shí)指針指向的對(duì)象有個(gè)函數(shù),提供了const&none const的,此時(shí),還是會(huì)調(diào)用non const的,所以,外界還是可以通過(guò)這個(gè)對(duì)象來(lái)做修改。
            2:2個(gè)不方便是,你必須對(duì)對(duì)象實(shí)現(xiàn)new和delete.
            下面來(lái)看下loki是怎么做的
            template<class T>
            struct ConstPropPtr
            {
            ??????? explicit ConstPropPtr(T* p) : ptr_(p) {}
            ??????? ~ConstPropPtr() { delete? ptr_; ptr_ = 0; }
            ??????? T* operator->()??? { return? ptr_; }
            ??????? T& operator*()??? { return *ptr_; }
            ??????? const T* operator->() const??? { return? ptr_; }
            ??????? const T& operator*()? const??? { return *ptr_; }
            ???
            private:
            ??????? ConstPropPtr();
            ??????? ConstPropPtr(const ConstPropPtr&);
            ??????? ConstPropPtr& operator=(const ConstPropPtr&);
            ??????? T* ptr_;
            };

            這個(gè)類提供了對(duì)問(wèn)題1的解決。下面會(huì)講解,主要的點(diǎn)是,對(duì)象不同于指針,對(duì)象能傳遞const屬性。
            下面看下pimlT的定義:
            template<class T, template<class> class Ptr = ConstPropPtr>
            struct PimplT
            {
            ??????? typedef T Impl;

            ??????? // declare pimpl
            ??????? typedef Pimpl<ImplT<T>, Ptr<ImplT<T> > > Type;

            ??????? // inherit pimpl
            ??????? typedef PimplOwner<ImplT<T>, Ptr<ImplT<T> > > Owner;
            };
            可以看到對(duì)Type
            的定義,下面的owner也不說(shuō)了,直接到Pimpl,

            template
            <???
            ??????? class T,
            ??????? typename Pointer = ConstPropPtr<T>
            >
            class Pimpl
            {
            public:

            ??????? typedef T Impl;

            ??????? Pimpl() : ptr_(new T)
            ??????? {}

            ??????? ~Pimpl()
            ??????? {
            ??????????? typedef char T_must_be_defined[sizeof(T) ? 1 : -1 ];
            ??????? }


            ??????? T* operator->()
            ??????? {
            ??????????? return ptr_.operator->();
            ??????? }

            ??????? T& operator*()
            ??????? {
            ??????????? return ptr_.operator*();
            ??????? }

            ??????? const T* operator->() const
            ??????? {
            ??????????? return ptr_.operator->();
            ??????? }

            ??????? const T& operator*() const
            ??????? {
            ??????????? return ptr_.operator*();
            ??????? }

            ??????? Pointer& wrapped()
            ??????? {
            ??????????? return ptr_;
            ??????? }

            ??????? const Pointer& wrapped() const
            ??????? {
            ??????????? return ptr_;
            ??????? }


            private:
            ??????? Pimpl(const Pimpl&);
            ??????? Pimpl& operator=(const Pimpl&);

            ??????? Pointer ptr_;
            };

            可以看到,這個(gè)類用了上面的ConstPropPtr從而使對(duì)象有了const屬性的傳遞。其他的,實(shí)際上,幫你操作了new,再ConstPropPtr里釋放,有點(diǎn)RAII的味道,剩下的完全模擬保存的指針的行為,即implT的實(shí)現(xiàn),從而使其能正確的操作對(duì)象。
            睡死了,早早結(jié)束
            ???????????????????????????????????????????????? alex_yuu
            posted @ 2007-02-11 15:52 agerlis 閱讀(411) | 評(píng)論 (0)編輯 收藏

            我的msn:agerlis@163.com
            我的email:agerlis@163.com
            我的qq:350457656
            posted @ 2007-02-11 15:32 agerlis 閱讀(331) | 評(píng)論 (3)編輯 收藏

            僅列出標(biāo)題  
            久久久久av无码免费网| 久久亚洲国产成人影院| 中文字幕无码久久人妻| 91精品国产高清久久久久久91| 欧美大香线蕉线伊人久久| 欧美黑人激情性久久| 精品久久久无码中文字幕| 91精品国产色综久久| 国产亚洲美女精品久久久| 国产成人精品久久| 久久久久国产成人精品亚洲午夜| 国产激情久久久久影院老熟女| 99久久精品免费国产大片| 日本三级久久网| 久久久久亚洲精品中文字幕| 欧美粉嫩小泬久久久久久久 | 久久久久国产| 中文字幕精品久久| 亚洲香蕉网久久综合影视 | 亚洲人成无码久久电影网站| 伊人久久大香线蕉精品不卡 | 久久笫一福利免费导航 | 三级韩国一区久久二区综合| 久久久久久久久久久| 久久ww精品w免费人成| 99热精品久久只有精品| 久久综合九色综合久99| 亚洲精品无码久久久久久| 精品熟女少妇av免费久久| 香蕉久久一区二区不卡无毒影院 | 久久综合亚洲色一区二区三区| 久久亚洲中文字幕精品有坂深雪 | 四虎国产精品免费久久| 亚洲AV无码久久精品蜜桃| 亚洲综合婷婷久久| 久久婷婷五月综合色奶水99啪 | 国产成人无码精品久久久性色| 国产精品久久久久久久久免费| 久久久久亚洲精品无码网址| 日韩人妻无码精品久久免费一 | 久久99精品久久久久久动态图|