• <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>
            posts - 94, comments - 250, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            Nebula3學習筆記(2): 核心庫

            Posted on 2008-12-14 21:04 Condor 閱讀(964) 評論(0)  編輯 收藏 引用

            核心子系統

            核心庫(Core namespace)實現了這些特性:

            • 一個實現了引用計數的RefCounted基類
            • 一個運行時類型信息系統(RTTI)
            • 一個模板智能指針, 用于處理RefCounted對象的生命周期
            • 一個由類名創建C++對象實例的工廠機制
            • 一個中央Server對象用于建立基本的Nebula3運行環境

            對象模型

            Nebula3在C++對象模型的基礎之上實現了下面這些新特性:

            • 基于引用計數和智能指針的生命周期管理
            • 基于類名或四字符編碼的對象創建
            • 一個運行時類型信息系統

            實現一個新的Nebula3類

            當實現一個新的類時首先要考慮它是一個傳統的C++類還是要從Core::RefCounted繼承. 以下幾點可以幫你找到答案:

            • 如果這個類需要使用Nebula3的擴展對象特性, 如引用計數, RTTI等, 則它必須從Core::RefCounted繼承.
            • 如果這個類是一個典型的小工具類, 如動態數組, 數學向量, 或其它相似的東西, 那么它從Core::RefCounted 繼承也沒有什么意義.

            從Core::RefCounted類繼承有一些限制:

            • RefCounted派生類不應該在棧上創建對象, 因為棧對象的生命周期是由C++來管理的(他們會在離開當前上下文時被銷毀, 從而繞過了Nebula3的引用計數生命周期 管理)
            • RefCounted的派生類只有一個默認的構造函數.
            • RefCounted的派生類必須有一個虛析構函數.
            • RefCounted的派生類不能進行拷貝, 因為這樣會造成引用計數機制混亂.

            要使用Nebula3的對象模型特性, 除了需要從Core::RefCounted繼承外, 還需要在頭文件新類的聲明中進行額外的標注:

            一個標準的RefCounted派生類一般這樣聲明:

            1: namespace MyNamespace

            2: {

            3: class MyClass : public Core::RefCounted

            4: {

            5: DeclareClass(MyClass);

            6: public:

            7: /// constructor

            8:     MyClass();

            9: /// destructor

            10: virtual ~MyClass();

            11: ...

            12: };

            13: RegisterClass(MyClass);

            注意DeclareClass()宏, 構造函數, 析構函數還有類外面的RegisterClass()宏. DeclareClass()宏加入了RTTI和工廠機制所需的最小代價的信息, 它隱藏了Nebula3的對象模型, 希望可以在不影響已有類的基礎進上進行內部機制的變更. RegisterClass()宏是可選的, 它把當前類在中央工廠進行注冊. 如果你知道這個類永遠不會由類名或四字符編碼進行創建, 這個宏可以省略.

            在這個類的.cpp文件里需要包含Nebula3特有的信息:

            1: namespace MyNamespace

            2: {

            3: ImplementClass(MyNamespace::MyClass, 'MYCL', Core::RefCounted);

            4:

            5: }

            ImplementClass()宏注冊類的RTTI機制, 第一個參數描述了類的名字(注意命名空間必須包含). 第二個參數是類的四字符編碼, 它必須是所有類中唯一的(如果有重復, 你會在啟動程序時得到一個錯誤提示). 第三個參數是父類的名字, 用于RTTI系統去構造類的關系樹.

            引用計數和智能指針

            Nebula3使用傳統的引用計數來管理對象的生命周期. 一個模板智能指針類Ptr<>對程序員隱藏了引用計數的實現細節. 一般來說, 應該一直使用智能指針指向RefCounted的派生對象, 除非你能肯定在給出的代碼塊中這個對象的引用計數不會發生變化.

            智能指針相對于一般指針有很多好處:

            • 訪問一個空指針會給你一個斷言警告而不是一個內存錯誤
            • 你不需要對引用計數的對象調用AddRef()或Release() (事實上如果你調了, 會了發生嚴重的錯誤)
            • 智能指針可以在容器類里良好地工作, 一個智能指針的數組會消除所有的一般指針需要的生命周期管理, 你永遠不需要考慮去釋放指針所指針的對象, 數組包含的像是真正的C++對象一樣
            • 用智能指針不需要考慮指針的所屬, 不需要為誰delete對象而煩惱

            智能指針也有一些缺點:

            • 性能: 拷貝和賦值會引起對象的引用計數的變化, 解除引用會引起指針的斷言檢查. 這導致的性能消耗一般是可以忽略的, 但是你最好保證它不在內部循環中發生.
            • 應該銷毀的對象還存在: 因為智能指針管理的對象只有在最后一個引用放棄時才會銷毀, 這樣會使對象存在超過預訂的時間. 這經常會導致一個BUG的產生. 不過引用計數泄露(程序退出時還仍然存在的對象)時Nebula3會提醒你.

            創建Nebula3對象

            從Core::RefCounted繼承的類可以通過3種不同的方式進行創建:

            直接通過靜態的Create方法:

            1: Ptr<MyClass> myObj = MyClass::Create();

            靜態的Create()方法是之前提到的DeclareClass()宏加入的, 相對于new操作符來說, 它并沒有多做什么. 注意正確使用智能指針來保存新建的對象.

            另一種創建方式是通過類名:

            1: using namespace Core;

            2: Ptr<MyClass> myObj = (MyClass*)Factory::Instance()->Create("MyNamespace::MyClass");

            當你在運行時通過類名來創建十分有用, 特別是對象的反序列化和腳本接口的使用. 注意類型轉換是必須的, 因為工廠的Creat()方法返回的是RefCounted指針.

            由類名創建的變種是根據四字符編碼進行創建:

            1: using namespace Core;

            2: using namespace Util;

            3: Ptr<MyClass> myObj = (MyClass*) Factory::Instance()->Create(FourCC('MYCL'));

            這個方法看上去沒有那個直觀, 但是它比類名創建快得多. 并且四字符編碼比類名占用的空間更少, 這更利于對象寫入二進制流或從中讀取.

            運行時類型信息系統

            Nebula3的RTTI系統可以讓你在運行時訪問對象的類型, 檢查一個對象是不是某個類的實例, 或者某個派生類的實例. 你也可以直接獲得一個對象的類名和四字符編碼. 所有這些功能是由DeclareClass() 和 ImplementClass() 宏在背后實現的.

            這時有示例程序:

            1:     using namespace Util;

            2:     using namespace Core;

            3:

            4: // check whether an object is instance of a specific class

            5: if (myObj->IsInstanceOf(MyClass::RTTI))

            6: {

            7: // it's a MyClass object

            8: }

            9:

            10: // check whether an object is instance of a derived class

            11: if (myObj->IsA(RefCounted::RTTI))

            12: {

            13: // it's a RefCounted instance or some RefCounted-derived instance

            14: }

            15:

            16: // get the class name of my object, this yields "MyNamespace::MyClass"

            17: const String& className = myObj->GetClassName();

            18:

            19: // get the fourcc class identifier of my object, this yields 'MYCL'

            20: const FourCC& fourcc = myObj->GetClassFourCC();

            你也可以向中央工廠查詢一個類是否已經注冊:

            1:     using namespace Core;

            2:

            3: // check if a class has been registered by class name

            4: if (Factory::Instance()->ClassExists("MyNamespace::MyClass"))

            5: {

            6: // yep, the class exists

            7: }

            8:

            9: // check if a class has been registered by class fourcc code

            10: if (Factory::Instance()->ClassExists(FourCC('MYCL')))

            11: {

            12: // yep, the class exists

            13: }

            Nebula3單件

            很多Nebula3的核心對象都是單件, 就是只存在一個實例, 并且所有其它對象都知道它.

            你可以通過靜態方法Instance()來訪問單件, 它返回唯一實例的一個指針. 返回的指針保證是合法的. 如果在調用Instance()方法時對象實例不存在, 一個斷點會被拋出:

            1: // obtain a pointer to the Core::Server singleton

            2:     Ptr<Core::Server> coreServer = Core::Server::Instance();

            你也可以檢查單件是否存在:

            1: // does the Core::Server object exist?

            2: if (Core::Server::HasInstance())

            3: {

            4: // yep, the core server exists

            5: }

            Nebula3提供了一些輔助的宏來實現單件:

            1: // declare a singleton class

            2: class MySingletonClass : public Core::RefCounted

            3: {

            4: DeclareClass(MySingletonClass);

            5: DeclareSingleton(MySingletonClass);

            6: public:

            7: /// constructor

            8:     MySingletonClass();

            9: /// destructor

            10: virtual ~MySingletonClass();

            11: ...

            12: };

            13:

            14: // implement the singleton class

            15: ImplementClass(MyNamespace::MySingletonClass, 'MYSC', Core::RefCounted);

            16: ImplementSingleton(MyNamespace::MySingletonClass);

            17:

            18: //------------------------------------------------------------------------------

            19: /**

            20:     Implements the Singleton constructor.

            21: */

            22: MySingletonClass::MySingletonClass()

            23: {

            24: ConstructSingleton;

            25: }

            26:

            27: //------------------------------------------------------------------------------

            28: /**

            29:     Implements the Singleton destructor.

            30: */

            31: MySingletonClass:~MySingletonClass()

            32: {

            33: DestructSingleton;

            34: }

            DeclareSingleton()和ImplementSingleton()宏跟DeclareClass()和ImplementClass()宏差不多.它們在類中添加了一些靜態方法(也就是Instance()和HasInstance()). 類的構造函數和析構函數必須包含ConstructSingletonDestructSingleton宏. ContructSingleton初始化了一個私有的單件指針并保證沒有其它的類實例存在(如果不是, 會拋出斷言). DestructSingleton讓私有的單件指針無效化.

            單件的訪問默認是只有本地線程. 這意味著在一個線程中創建的單件無法被其他線程訪問. 這使得”并行Nebula”大大簡化了多線程編程. “并行Nebula”的基本思想是, 一個典型的Nebula3應用程序包含一些”Fat線程”, 每一個Fat線程都是運行在一個單獨的CPU核心上. Fat線程可以用于實現異步IO, 渲染, 物理等等. 每一個Fat線程都初始化了它們自己的Nebula3運行環境, 它們執行特性任務所需的最少依賴. 這基本上消除了大部分Nebula3代碼的同步問題, 并且把線程相關的代碼集中到一個明確定義的代碼區域中. “并行Nebula”的另一個好處就是, 程序員在多線程環境中編程時不需要關心太多. 大多數Nebula3代碼看起來就像單線程代碼一樣, 但是它們卻運行在各自的Fat線程中.

            性能與內存占用的考慮

            Nebula3核心層的一個設計目標就是減少底層代碼的內存占用, 來更好的適應微型平臺, 像手持設備. 這里有一些已經完成的目標:

            • RefCounted 類在每個實例中只增加了4byte用于引用計數.
            • RTTI機制在開頭增加了30 到 60 byte, 但是這是對于每個類來說的, 而是不是每個實例.
            • 一個智能指針僅僅4 byte, 就像普通指針一樣.
            • 一些監控結構只會在debug模型下創建, 特別是用來檢測引擎計數泄露的RefCountedList.

            這里一些用三種不種的創建方法創建一百萬個RefCounted 對象所需的時間信息. 這些時間信息是在臺Intel Pentium 800 MHz的筆記本上得出的.  

            • Create(): 0.29 seconds
            • FourCC: 0.65 seconds
            • 類名: 1.45 seconds
            中文字幕日本人妻久久久免费| 久久av高潮av无码av喷吹| 亚洲综合熟女久久久30p| 久久人人爽人人爽人人片AV高清 | 久久久亚洲欧洲日产国码aⅴ| 久久久久亚洲av无码专区导航 | 国产激情久久久久影院老熟女| 久久亚洲中文字幕精品一区| 国产69精品久久久久APP下载| 69久久精品无码一区二区| 久久中文字幕视频、最近更新| 久久久久青草线蕉综合超碰| 色综合合久久天天综合绕视看 | 久久精品国产99久久丝袜| 中文精品99久久国产 | 久久亚洲精品中文字幕三区| 久久亚洲高清综合| 久久久久久免费一区二区三区 | 色综合久久最新中文字幕| 久久大香萑太香蕉av| 99久久国产免费福利| 久久国产热精品波多野结衣AV| 亚洲精品NV久久久久久久久久 | www.久久99| 无码伊人66久久大杳蕉网站谷歌 | 99久久精品国产一区二区蜜芽 | 综合久久精品色| 久久午夜综合久久| 国产精品免费久久久久电影网| 久久久久九九精品影院| 色综合久久久久无码专区| 久久综合色之久久综合| 国产精自产拍久久久久久蜜| 无码超乳爆乳中文字幕久久| 久久99精品久久久大学生| 久久综合色老色| 亚洲国产精品综合久久一线| 久久天天躁狠狠躁夜夜2020老熟妇 | 中文字幕久久精品| 要久久爱在线免费观看| 亚洲欧美日韩精品久久亚洲区 |