<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    PS,1880后程序員

    看不完的牙,寫不完的程序,跑不完的步。
    隨筆 - 97, 文章 - 34, 評論 - 10, 引用 - 0
    數(shù)據(jù)加載中……

    C++ Primer 之 讀書筆記 第十八章 特殊工具與技術(shù)

     

    Chapter 18. 特殊工具與技術(shù)

     

    18.1 優(yōu)化內(nèi)存分配Optimizing Memory Allocation

    分配內(nèi)存和創(chuàng)建對象是兩個不同的概念。分配內(nèi)存,并不一定會立即創(chuàng)建對象。同樣,內(nèi)存釋放和對象撤銷也是兩個不同的概念。

     

    18.1.1. C++ 中的內(nèi)存分配

    new操作:給指定的類型分配內(nèi)存并在新分配的內(nèi)存上構(gòu)造指定類型的對象。

    在未構(gòu)造的內(nèi)存上給對象賦值,而不是初始化這個對象,這種賦值是未定義的。對很多類來說,這樣做會導致運行期崩潰。賦值包括刪除現(xiàn)有的對象,如果不存在現(xiàn)有對象,那么這個賦值操作就會導致災難性的結(jié)果。Assigning to an object in unconstructed memory rather than initializing it is undefined. For many classes, doing so causes a crash at run time. Assignment involves obliterating the existing object. If there is no existing object, then the actions in the assignment operator can have disastrous effects.

    C++提供兩種方法分配和釋放未構(gòu)造的內(nèi)存

    1. allocator
    2. newdelete操作符

    C++提供兩種方法創(chuàng)建和銷毀對象:

    1. allocator
    2. new操作符
    3. 直接調(diào)用對象的析構(gòu)函數(shù)(但是此時只是把對象占用的內(nèi)存變成了為構(gòu)造內(nèi)存,但是這個內(nèi)存并沒有釋放哦)
    4. uninitialized_fill and uninitialized_copy,是拷貝不是賦值

    18.1.2. allocator

    這是一個模板類,提供類型化的內(nèi)存分配,對象創(chuàng)建和撤銷。它把內(nèi)存分配和對象創(chuàng)建這兩件事情分開來。當一個allocator對象分配內(nèi)存時間,它只是根據(jù)給定的類型分配出空間,這個空間的大小可以用來保存給定類型的對象。但是這時,所分配的空間還沒有構(gòu)建。這就相當于預先分配preallocation

    allocator<T> a;

    定義allocator對象a,按類型T分配內(nèi)存。

    a.allocate(n)

    分配未構(gòu)造內(nèi)存,這個內(nèi)存的大小是n個類型T的對象

    使用allocator管理類成員數(shù)據(jù)

    這里是用vector類來舉例說明。從vector的工作機制中可以看到:如果沒有空閑的單元,vector重新分配內(nèi)存。這樣獲得新的空間后,vector拷貝當前現(xiàn)有的對象到新的內(nèi)存空間,然后釋放舊的內(nèi)存空間。If there isn't a free element, then the vector is reallocated: The vector obtains new space, copies the existing elements into that space, adds the new element, and frees the old space.因此從這個工作機理中可以看出vector的效率是比較差的。

    下面的這段代碼很好的說明了alloctor是如何管理類成員數(shù)據(jù)的。

    1. allocator分配內(nèi)存空間一定是和類型相關(guān)的。因此在Vector里面定義了靜態(tài)成員alloc

    static std::allocator<T> alloc; // object to get raw memory

    1. alloc.allocate()返回值是一個指定類型的指針。
    2. 先調(diào)用析構(gòu)函數(shù)alloc.destroy(),再釋放空間alloc.deallocate()

    template <class T> void Vector<T>::reallocate()

     {

         std::ptrdiff_t size = first_free - elements;

         std::ptrdiff_t newcapacity = 2 * max(size, 1);

         // allocate space to hold newcapacity number of elements of type T

         T* newelements = alloc.allocate(newcapacity);

         // construct copies of the existing elements in the new space

         uninitialized_copy(elements, first_free, newelements);

         // destroy the old elements in reverse order

         for (T *p = first_free; p != elements; /* empty */ )

            alloc.destroy(--p);

         // deallocate cannot be called on a 0 pointer

         if (elements)

             // return the memory that held the elements

             alloc.deallocate(elements, end - elements);

         // make our data structure point to the new elements

         elements = newelements;

         first_free = elements + size;

         end = elements + newcapacity;

     }

    18.1.3. operator new 函數(shù)和 operator delete 函數(shù)

    operator newoperator delete和標準庫中的其它操作符有些不同,它們是不能重載的。

    operator newoperator delete有兩種重載版本:

    void *operator new(size_t);       // allocate an object

    void *operator new[](size_t);     // allocate an array

    void *operator delete(void*);     // free an object

    void *operator delete[](void*);   // free an array

    可以用operator newoperator delete模擬allocator

    • 分配內(nèi)存空間

    T* newelements = alloc.allocate(newcapacity);

    改編成

    T* newelements = static_cast<T*>(operator new[](newcapacity * sizeof(T)));

    • 釋放內(nèi)存空間

    alloc.deallocate(elements, end - elements);

    改編成

    operator delete[](elements);

    一般而言,使用 allocator 比直接使用 operator new operator delete 函數(shù)更為類型安全。In general, it is more type-safe to use an allocator rather than using the operator new and operator delete functions directly.

    18.1.4. 定位 new 表達式Placement new Expressions

    定位new表達式實際上就是要實現(xiàn)在已經(jīng)分配的內(nèi)存空間上構(gòu)造對象的功能。

    基本形式:

    new (place_address) type

    new (place_address) type (initializer-list)

    對比construct

    alloc.construct(first_free, t);

    等價于:

    new (first_free) T(t);

    ·         定位new表達式更加靈活。通過下面的Example可以看出二者之間的區(qū)別:

    allocator<string> alloc;

    string *sp = alloc.allocate(2); // allocate space to hold 2 strings

    // two ways to construct a string from a pair of iterators

    new (sp) string(b, e);                    // construct directly in place

    alloc.construct(sp + 1, string(b, e));   // build and copy a temporary

    1.                當定位new表達式初始化一個對象時,它使用構(gòu)造函數(shù),直接創(chuàng)建對象。When placement new initializes an object, it can use any constructor, and builds the object directly.

    2.                alloc.construct()函數(shù)總是使用拷貝構(gòu)造函數(shù)The construct function always uses the copy constructor.

    ·         從性能角度考慮,alloc.construct()函數(shù)總是要構(gòu)造臨時對象然后再拷貝它。

    ·         另外有些類是不支持copy構(gòu)造函數(shù)的,這種情況下就只能用定位new了。

    18.1.5. 顯式析構(gòu)函數(shù)的調(diào)用(Explicit Destructor Invocation)

    既然可以通過定位new調(diào)用構(gòu)造函數(shù),那么對應于此,還可以通過顯示調(diào)用析構(gòu)函數(shù)來取消對象。

    調(diào)用操作符delete不會執(zhí)行析構(gòu)函數(shù),而只是釋放所指向的內(nèi)存。Calling the operator delete function does not run the destructor; it only frees the indicated memory.

    18.1.6. 類特定的 new deleteClass Specific new and delete

    這部分要說明的是類如何優(yōu)化new表達式的行為(optimizing the behavior of new expressions.)。

    這件事的理論依據(jù)是,類通過定義自己的成員,操作符newdelete,就可以管理其對象使用的內(nèi)存。A class may manage the memory used for objects of its type by defining its own members named operator new and operator delete.

    當編譯器看到類類型的newdelete表達式的時候,它先看這個類是不是定義了操作符newdelete成員。如果類定義自己的這兩個操作符函數(shù),編譯器就直接調(diào)用這些函數(shù)分配和釋放對象的內(nèi)存。否則,編譯器調(diào)用標準庫里的newdelete版本。When the compiler sees a new or delete expression for a class type, it looks to see if the class has a member operator new or operator delete. If the class defines (or inherits) its own member new and delete functions, then those functions are used to allocate and free the memory for the object. Otherwise, the standard library versions of these functions are called.

    newdelete成員函數(shù)

    重載newdelete包括一些限定條件:

    1. 首先必須是成對出現(xiàn),就是說如果重載new,也必須重載deleteIf a class defines either of these members, it should define both of them.
    2. 必須定義為靜態(tài)函數(shù)static

    L需要復習下下virtual析構(gòu)函數(shù),不virtual那又怎么樣?

    當一個基類指針指向的是一個派生類的對象時,如果析構(gòu)函數(shù)是virtual的,那么編譯器在運行期動態(tài)綁定到底調(diào)用哪個類的析構(gòu)函數(shù)。但是如果析構(gòu)函數(shù)沒有聲明為virtual,編譯器在編譯期就確定調(diào)用基類的析構(gòu)函數(shù),這就是靜態(tài)綁定

    new

    返回值類型是void*,形參類型是size_t

    delete

    返回值類型是void,形參類型是一個參數(shù)的void*,或者是兩個參數(shù)的void*size_t

    不得不說這部分講的太簡單了,只好從Google上再找些資料學習哈。

    定義:

    #include <malloc.h>

    struct base

    {

        base()

        {

            throw int(3);

        }

        ~base() {}

        void* operator new( size_t nsize, const char*,int)

        {

            void* p = malloc( nsize );

            return p;

        } 

        void operator delete( void *p)

        {

            free(p);

        }

        void operator delete( void* p,const char*,int)

        {

            free( p );

        }

    };

    調(diào)用:

    nt main( void )

    {

        base* p = null;

        try

        {

            p = new base;

            delete p;

        }

        catch(...)

        {

        }

        return 0;

    }

    數(shù)組操作符new[]delete[]

    覆蓋類特定的內(nèi)存分配(Overriding Class-Specific Memory Allocation

    如何強制調(diào)用全局的操作符newdelete

    Type *p = ::new Type; // uses global operator new

    ::delete p;           // uses global operator delete

    18.1.7. 一個內(nèi)存分配器基類(A Memory-Allocator Base Class)

    這個部分就是這一節(jié)所講內(nèi)容的一個完整的實例。

    CachedObj可以看做是一種freelist

    freelist是啥?Google了一下下,KAO,原來有N多種freelist的實現(xiàn)。這是一種內(nèi)存管理技術(shù),包括預先分配沒有構(gòu)造對象的內(nèi)存,對象只在需要時在這些內(nèi)存上創(chuàng)建。當對象釋放時,它們所占用的內(nèi)存返回給預先分配的內(nèi)存而不是直接返回給系統(tǒng)。Memory management technique that involves preallocating unconstructed memory to hold objects that will be created as needed. When objects are freed, their memory is put back on the free list rather than being returned to the system.

    定義代碼:

    template <class T> class CachedObj {

     public:

          void *operator new(std::size_t);

          void operator delete(void *, std::size_t);

          virtual ~CachedObj() { }

     protected:

          T *next;

     private:

          //add_to_freelist的作用就是想freelist中添加對象

          static void add_to_freelist(T*);

          //靜態(tài)成員負責管理freelist,對于每種類型只需要一個freelist

          static std::allocator<T> alloc_mem;

          //freestor就是指向freelist表頭的指針。

          static T *freeStore;

          //chunk是一次預分配內(nèi)存空間的大小。

          static const std::size_t chunk;

     };

    使用CachedObj - 派生類定義

    1):

    class Screen: public CachedObj<Screen> {

       // interface and implementation members of class Screen are unchanged

     };

    2):

    template <class Type>

     class QueueItem: public CachedObj< QueueItem<Type> > {

       // remainder of class declaration and all member definitions unchanged

     };

    分配(Allocation)如何工作

    new表達式:QueueItem<Type> *pt = new QueueItem<Type>(val);

    1. 使用QueueItem<T>::operator newfreelist為對象分配空間。
    2. 在分配的空間上,使用類型Tcopy構(gòu)造函數(shù)構(gòu)建對象。

    deletedelete pt;

    1. 執(zhí)行QueueItem的析構(gòu)函數(shù)。
    2. 把對象所占用的內(nèi)存返還給freelist

    定義操作符new

    功能:從freelist里獲得一個對象的內(nèi)存。

    template <class T>

     void *CachedObj<T>::operator new(size_t sz)

     {

           // 鏈表中的數(shù)據(jù)類型必須一致

           if (sz != sizeof(T))

               throw std::runtime_error

                ("CachedObj: wrong size object in operator new");

           if (!freeStore) {

               // 鏈表為空,分配新的內(nèi)存

               T * array = alloc_mem.allocate(chunk);

               // 把新分配的內(nèi)存單元追加到freelistfreelist是個鏈表,所以把數(shù)組轉(zhuǎn)換成鏈表,這樣每個對象的next指針都指向下一個對象

               for (size_t i = 0; i != chunk; ++i)

                     add_to_freelist(&array[i]);

           }

           // freestore總是指向下一個有效的單元

           T *p = freeStore;

           freeStore = freeStore->CachedObj<T>::next;

           return p;   // constructor of T will construct the T part of the object

     }

    定義delete操作符

    功能:就是要把對象占用的內(nèi)存還給freelist

    template <class T> void CachedObj<T>::operator delete(void *p, size_t)

     {

         if (p != 0)

             // put the "deleted" object back at head of freelist

             add_to_freelist(static_cast<T*>(p));

     }

    add_to_freelist成員

    template <class T> void CachedObj<T>::add_to_freelist(T *p)

     {

        //這是一個小技巧,為的是避免調(diào)用派生類的next成員(如果存在)

        p->CachedObj<T>::next = freeStore;

        freeStore = p;

     }

    18.2 運行期類型識別Run-Time Type Identification

    通過兩個操作符提供RTTI

    1. typeid:返回指針或者引用指向的對象的實際類型。
    2. dynamic_cast:把指向基類的對象的指針或者引用轉(zhuǎn)換成派生類的指針或引用。

    對于具有虛函數(shù)的類,RTTI在運行期執(zhí)行;對于其它的類型是在編譯期執(zhí)行的。The RTTI operators execute at run time for classes with virtual functions, but are evaluated at compile time for all other types.

    dynamic_cast:動態(tài)強制類型轉(zhuǎn)換

    使用動態(tài)強制類型轉(zhuǎn)換要小心。在任何可能的情況下,定義和使用虛函數(shù)比直接接管類型管理好得多。Dynamic casts should be used with caution. Whenever possible, it is much better to define and use a virtual function rather than to take over managing the types directly.

    18.2.1. dynamic_cast 操作符

    dynamic_cast操作符實際上執(zhí)行了兩種操作:

    1. 驗證要執(zhí)行的強制類型轉(zhuǎn)換是不是有效。It begins by verifying that the requested cast is valid.
    2. 只有當強制類型轉(zhuǎn)換有效時,操作符才執(zhí)行實際的轉(zhuǎn)換操作。Only if the cast is valid does the operator actually do the cast.

    使用dynamic_cast 操作符

    大師給出了dynamic_cast操作符的使用方法,并例舉出這樣做的三大好處,總而言之就是盡量把代碼出錯的幾率降到最小。

    if (Derived *derivedPtr = dynamic_cast<Derived*>(basePtr))

     {

         // use the Derived object to which derivedPtr points

     } else { // BasePtr points at a Base object

         // use the Base object to which basePtr points

     }

    在條件語句中使用dynamic_cast 操作符保證強制轉(zhuǎn)換以及轉(zhuǎn)換結(jié)果測試在一個表達式中。Performing a dynamic_cast in a condition ensures that the cast and test of its result are done in a single expression.

    這看上去很簡單,但是很重要,因為這樣可以降低程序出錯的概率。

    使用 dynamic_cast 和引用類型

    對于引用類型的強制轉(zhuǎn)換,和指針的略有不同,這是因為引用不能是空null

    void f(const Base &b)

     {

        try {

            const Derived &d = dynamic_cast<const Derived&>(b);

        // use the Derived object to which b referred

        } catch (bad_cast) {

            // handle the fact that the cast failed

        }

     }

    18.2.2. typeid 操作符

    typeid操作符的操作數(shù)不是類類型或者是類類型但是不包含虛函數(shù),typeid操作符指定的是操作數(shù)的靜態(tài)類型。當操作數(shù)是定義了至少一個虛函數(shù)的類類型時,類型是在運行期計算出來的。When the operand is not of class type or is a class without virtual functions, then the typeid operator indicates the static type of the operand. When the operand has a class-type that defines at least one virtual function, then the type is evaluated at run time.

    使用typeid操作符

    •  

    Base *bp;

     Derived *dp;

     // compare type at run time of two objects

     if (typeid(*bp) == typeid(*dp)) {

         // bp and dp point to objects of the same type

     }

    •  

    // test whether run time type is a specific type

     if (typeid(*bp) == typeid(Derived)) {

         // bp actually points to a Derived

     }

    18.2.3. RTTI 的使用

    這是一個RTTI使用的簡單的例子:

    問題提出:如何定義基類、派生類的相等操作符

    相等的含義是:

    (1) 類型相同

    (2) 指定數(shù)據(jù)成員的值相同

    愚蠢的方法是針對每個派生類的組合都去重載操作符“==”。至于多愚蠢想象一下就夠了哦J

    18.2.4. type_info

    • 這個類和編譯器相關(guān),不同的編譯器對這個類的定義可能存在差異
    • type_info類的構(gòu)造函數(shù)和拷貝各種哦函數(shù)都是私有的private,唯一獲得type_info對象的方法就是通過typeid操作符。
    • 成員函數(shù)name的返回值依賴于編譯器。但是對于同一個類型,它的返回值是唯一的。這句話的含義是代碼中是不能出現(xiàn)if(typeid(obj).name()==”string”)這樣的代碼,因為不同的編譯器name函數(shù)的返回值是不一樣的。

    std::string obj;

    if(typeid(obj).name()==”string”)     //Error

    if(typeid(obj)== typeid(std::string) ) //OK

    18.3 類成員指針Pointer to Class Member

    定義

    指向數(shù)據(jù)成員的指針

    string Screen::*ps_Screen = &Screen::contents;

    指向成員函數(shù)的指針

    char (Screen::*pmf)() const = &Screen::get;

    pmf是一個指向Screen類的無形參的get函數(shù)的指針。

    Screenget函數(shù)的定義:

    char get() const;

    char get(index ht, index wd) const;

    帶形參的定義:

    char (Screen::*pmf2)(Screen::index, Screen::index) const;

    pmf2 = &Screen::get;

    使用typedef為成員指針定義別名

    // Action is a type name

    typedef char (Screen::*Action)(Screen::index, Screen::index) const;

    這樣上面的定義就可以簡化成:

    Action get = &Screen::get;

    使用類成員指針

    類成員指針說來說去的,其實還是指針,是指針,就對應有解引用操作(*)和箭頭操作(->)

    使用指向成員函數(shù)的指針

    // pmf points to the Screen get member that takes no arguments

    char (Screen::*pmf)() const = &Screen::get;

    Screen myScreen;

    char c1 = myScreen.get();      // call get on myScreen

    char c2 = (myScreen.*pmf)();   // equivalent call to get

    Screen *pScreen = &myScreen;

    c1 = pScreen->get();     // call get on object to which pScreen points

    c2 = (pScreen->*pmf)(); // equivalent call to get

    使用指向數(shù)據(jù)成員的指針

    Screen::index Screen::*pindex = &Screen::width;

    Screen myScreen;

    // equivalent ways to fetch width member of myScreen

    Screen::index ind1 = myScreen.width;      // directly

    Screen::index ind2 = myScreen.*pindex;    // dereference to get width

    Screen *pScreen;

    // equivalent ways to fetch width member of *pScreen

    ind1 = pScreen->width;        // directly

    ind2 = pScreen->*pindex;      // dereference pindex to get width

    應用

    成員指針的一個具體的應用就是成員指針函數(shù)列表(Pointer-to-Member Function Tables)。說來也很簡單,就是把函數(shù)指針保存成Array,根據(jù)下標來索引調(diào)用哪一個函數(shù)。因為這些函數(shù)被定義成了類成員函數(shù),這就用到了成員函數(shù)指針。這也算是一種典型的應用了。

    18.4 內(nèi)嵌類Nested Classes

    這內(nèi)嵌類實際上是在它的外圍類enclosing class里定義了一種新的類型成員。A nested class defines a type member in its enclosing class.

    哦。。。這讓我想到的是Java中的內(nèi)部類,這兩個東西是不是類似L

    18.4.1 實現(xiàn)內(nèi)嵌類

    定義內(nèi)嵌類

    template <class Type> class Queue {

         // interface functions to Queue are unchanged

     private:

         // public members are ok: QueueItem is a private member of Queue

         // 只有Queue和它的友元可以訪問QueueItem

         struct QueueItem {

             QueueItem(const Type &);

             Type item;            // value stored in this element

             QueueItem *next;      // pointer to next element in the Queue

         };

         QueueItem *head;      // pointer to first element in Queue

         QueueItem *tail;      // pointer to last element in Queue

     };

    定義內(nèi)嵌類成員

    在哪里定義?

    1. 必須和外圍類的定義在同一個作用域里。
    2. 如果內(nèi)嵌類的成員在自身類的外面定義,那么她是不能定義在外圍類里的。很好理解哦,內(nèi)嵌類的成員不是外圍類的成員嘛。

    下面這個例子(噢噢,不是花生),就是定義QueueItem的構(gòu)造函數(shù):

    // defines the QueueItem constructor

    // for class QueueItem nested inside class Queue<Type>

    //這是QueueItem的構(gòu)造函數(shù)定義它是內(nèi)嵌在Queue<Type>作用域的

    template <class Type>

     Queue<Type>::QueueItem::QueueItem(const Type &t): item(t), next(0) { }

    在外圍類之外定義內(nèi)嵌類

    定義Queue類,只要前向聲明QueueItem是內(nèi)嵌類。

    template <class Type> class Queue {

     // interface functions to Queue are unchanged

     private:

          struct QueueItem; // forward declaration of nested type QueueItem

          QueueItem *head; // pointer to first element in Queue

          QueueItem *tail; // pointer to last element in Queue

     };

    在另一個文件中定義QueueItem,注意一定要用限定struct Queue<Type>

     template <class Type>

     struct Queue<Type>::QueueItem {

          QueueItem(const Type &t): item(t), next(0) { }

          Type item;        // value stored in this element

          QueueItem *next; // pointer to next element in the Queue

     };

    內(nèi)嵌模板實例化

    當外圍類模板實例化時,內(nèi)嵌類是不會自動實例化的。A nested class of a class template is not instantiated automatically when the enclosing class template is instantiated.內(nèi)嵌類只有在上下文中用到時才實例化。就是說:Queue<int> qi;只是實例化了Queue<int>而沒有實例化 QueueItem<int>

    18.4.2 內(nèi)嵌類作用域的名字查找

    當處理類成員聲明時,。當處理定義時,完整的內(nèi)嵌類或者外圍類必須在同一作用域里。When processing the declarations of the class members, any name used must appear prior to its use. When processing definitions, the entire nested and enclosing class(es) are in scope.

    18.5 聯(lián)合Union

    定義Union

    union TokenValue {

         char   cval;

         int    ival;

         double dval;

     };

    限制條件:

    1. 不能包含有靜態(tài)成員。
    2. 不能包含引用。
    3. 不能包含那些具有構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值操作符的類類型的對象。
    4. 不能包含有虛函數(shù)。

    使用

    定義

    // 初始化TokenValue,但是只能為第一個成員使用初始化式

    TokenValue first_token = {'a'}; 

    // 未初始化TokenValue對象

    TokenValue last_token;         

    // 定義指向TokenValue對象的指針

    TokenValue *pt = new TokenValue;

    使用

    last_token.cval = 'z';

    pt->ival = 42;

    嵌套Union

    class Token {

     public:

         // indicates which kind of value is in val

         enum TokenKind {INT, CHAR, DBL};

         TokenKind tok;

         union {             // unnamed union

             char   cval;

             int    ival;

             double dval;

         } val;              // member val is a union of the 3 listed types

     };

    匿名Union

    因為匿名的Union沒有提供訪問其成員的方法,因此Union的成員作為定義的作用域的一部分直接訪問。Because an anonymous union provides no way to access its members, the members are directly accessible as part of the scope where the anonymous union is defined.

    class Token {

     public:

         // indicates which kind of token value is in val

         enum TokenKind {INT, CHAR, DBL};

         TokenKind tok;

         union {                 // anonymous union

             char   cval;

             int    ival;

             double dval;

         };

     };

    訪問:

    Token token;

     switch (token.tok) {

     case Token::INT:

          token.ival = 42; break;

     case Token::CHAR:

          token.cval = 'a'; break;

     case Token::DBL:

          token.dval = 3.14; break;

     }

    18.6 局部類Local Classes

    跳過,跳過。。。

    18.7固有的不可移植的特征( Inherently Nonportable Features

    portable:可移植的。

    這一節(jié)所涉及的內(nèi)容:

    ·         如何更加容易的和硬件接口:位域和volatile

    ·         如何更加容易的于其它語言的程序接口:鏈接指示linkage directives

    18.7.1. 位域

    位域在內(nèi)存中的存儲和機器相關(guān)。The layout in memory of a bit-field is machine-dependent.

    typedef unsigned int Bit;

     class File {

         Bit mode: 2;

         Bit modified: 1;

         Bit prot_owner: 3;

         Bit prot_group: 3;

         Bit prot_world: 3;

         // ...

     };

    關(guān)于位域有很多特殊性,羅列出來:

    1. 位域最好是無符號類型。it is best to make a bit-field an unsigned type.
    2. 地址操作符(&)不能應用于位域,因此也就不存在有指向位域的指針。The address-of operator (&) cannot be applied to a bit-field
    3. 位域也不能是類的靜態(tài)成員。Nor can a bit-field be a static member of its class.
    4. 超過一個比特的位域通常要使用內(nèi)置的位操作符來控制。Bit-fields with more than one bit are usually manipulated using the built-in bitwise operators

    enum { READ = 01, WRITE = 02 }; // File modes

     int main() {

         File myFile;

         myFile.mode |= READ; // set the READ bit

         if (myFile.mode & READ) // if the READ bit is on

             cout << "myFile.mode READ is set"n";

     }

    18.7.2. volatile 限定符

    當一個對象是通過編譯器控制或者檢測以外的方式修改,這個對象就聲明為volatile 。這意味著編譯器不會對這個對象進行優(yōu)化。An object should be declared volatile when its value might be changed in ways outside either the control or detection of the compiler.

    volatile Task *curr_task; //執(zhí)行volatile Task對象的指針

    volatile int ixa[max_size]; 

    volatile Screen bitmap_buf; //數(shù)據(jù)成員都是volatile

    羅列出噩夢般的N多種寫法的含義L

    volatile int v;     // v is a volatile int

    int *volatile vip; // vip是指向intvolatile指針

    volatile int *ivp; // ivp是指向volatile int的指針

    volatile int *volatile vivp;// vivp是指向volatile intvolatile指針

    int *ip = &v; // error: must use pointer to volatile

    *ivp = &v;    // ok: ivp is pointer to volatile

    vivp = &v;    // ok: vivp is volatile pointer to volatile

    18.7.3. 鏈接指示: extern "C"        

    目的是為了解決程序調(diào)用其它語言的程序的函數(shù)。

    C++使用連接指示linkage directives來指明非C++函數(shù)的語言。

    聲明非C++函數(shù)

    // 單個聲明

    extern "C" size_t strlen(const char *);

    // 復合聲明

    extern "C" {

        int strcmp(const char*, const char*);

        char *strcat(char*, const char*);

    }

    導出C++函數(shù)到其它語言

    extern "C" double calc(double dparm) { /* ... */ }

    重載函數(shù)和鏈接指示

    這取決于編程語言是不是支持重載,如果是C,不支持重載,那當然就不行嘍。

    在一組重載函數(shù)中只能為一個 C 函數(shù)指定鏈接指示。a linkage directive can be specified only for one C function in a set of overloaded functions.

    // error: two extern "C" functions in set of overloaded functions

    extern "C" void print(const char*);

    extern "C" void print(int);

    函數(shù)指針

    聲明:

    注意:因為這是一個C指針,因此它是不能指向C++函數(shù)的。A pointer to a C function does not have the same type as a pointer to a C++ function.

    //pf是一個指向C函數(shù)的指針,函數(shù)的返回值是void;形參是int

    extern "C" void (*pf)(int);

    posted on 2009-08-28 08:35 amenglai 閱讀(764) 評論(0)  編輯  收藏 所屬分類: C++ Primer 之 讀書筆記

    主站蜘蛛池模板: 精品国产污污免费网站入口在线| 久久久久亚洲av无码专区喷水| 国产高清在线免费视频| 成人毛片免费在线观看| 亚洲人成网站免费播放| av免费不卡国产观看| 国产精品成人免费福利| 亚洲免费中文字幕| 日本黄网站动漫视频免费| 3344永久在线观看视频免费首页 | 久久国产亚洲精品麻豆| 国产亚洲精品自在线观看| 国产亚洲精品免费视频播放 | 4虎永免费最新永久免费地址| 69av免费观看| 成年人免费视频观看| 国产午夜免费秋霞影院| 亚洲毛片网址在线观看中文字幕| ZZIJZZIJ亚洲日本少妇JIZJIZ| 久久久久亚洲AV成人网人人网站 | 日韩免费a级在线观看| 又粗又硬又黄又爽的免费视频| 亚洲国产精品无码久久九九| 亚洲午夜福利AV一区二区无码| 亚洲日本中文字幕区| 亚洲成aⅴ人在线观看| 亚洲人成网站在线在线观看| 黄床大片30分钟免费看| 青青操免费在线视频| 222www免费视频| 免费无码不卡视频在线观看| 亚洲精品WWW久久久久久| 亚洲国产精品成人久久| 亚洲人成伊人成综合网久久| 男男gay做爽爽免费视频| a毛片免费全部在线播放**| 久久九九兔免费精品6| 国产自产拍精品视频免费看| 亚洲中文字幕日产乱码高清app| 久久亚洲精品中文字幕| 亚洲精品国产第一综合99久久|