青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 13, comments - 4, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

Imperfect C++ 讀書筆記(三)

Posted on 2008-11-20 00:28 Batiliu 閱讀(395) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 讀書筆記

數(shù)組和指針

首先我們來看一個(gè)經(jīng)典的C/C++求數(shù)組元素個(gè)數(shù)的解決方案:

#define NUM_ELEMENTS(x) (sizeof((x)) / sizeof((x)[0]))

利用C/C++編譯器將表達(dá)式 ar[n] 在編譯器解釋為 *(ar+n) 的特性,我們可以提供一個(gè)更“先進(jìn)”的版本:

#define NUM_ELEMENTS(x) (sizeof((x)) / sizeof(0[(x)]))

這種下標(biāo)索引的可交換性,只對(duì)內(nèi)建的下標(biāo)索引操作符有效,這一限制可以被用于約束NUM_ELEMENTS宏只對(duì)數(shù)組/指針有效,而拒絕重載了下標(biāo)索引操作符的類類型。

 

接下來,我們來看NUM_ELEMENTS的實(shí)際運(yùn)用:

int ar[10];
cout << NUM_ELEMENTS(ar) << endl;        // 毋庸置疑,輸出為10。
...
void fn(int ar[10])
{
    cout << NUM_ELEMENTS(ar) << endl;    // 本行結(jié)果呢?如果你說10,那么將會(huì)使你大失所望,
}                                        // 事實(shí)上,程序輸出為1。

看起來一切都井井有條,問題究竟出在哪里呢?呃,是這樣的,在C/C++中你無法將數(shù)組傳給函數(shù)!在C里面,數(shù)組被傳遞函數(shù)時(shí)總是被轉(zhuǎn)換成指針,非常干脆地阻止了你獲取數(shù)組大小的企圖。而C++基于兼容性的考慮,亦是如此。

所以先前給出的NUM_ELEMENTS宏定義依賴于預(yù)處理器進(jìn)行的文本替換,因而存在一個(gè)嚴(yán)重的缺陷:如果我們(不小心)將它應(yīng)用到一個(gè)指針身上,文本替換出來的結(jié)果將是錯(cuò)誤的。

 

幸運(yùn)的是,我們可以利用大多數(shù)現(xiàn)代編譯器都支持的一個(gè)特性來將數(shù)組和指針區(qū)別對(duì)待,那就是:從數(shù)組到指針的轉(zhuǎn)換(退化)在引用類型的模板實(shí)參決議中并不會(huì)發(fā)生。因而我們可以重新定義NUM_ELEMENTS宏為:

template<int N>
struct array_size_struct
{
    byte_t c[N];
};
 
template<typename T, int N>
array_size_struct<N> static_array_size_fn(T(&)[N]);
 
#define NUM_ELEMENTS(x) sizeof(static_array_size_fn(x).c)

其基本原理是:聲明(但不定義)一個(gè)模板函數(shù),它接受一個(gè)元素類型為T、大小為N的數(shù)組的引用。這樣一來,指針類型以及用戶自定義類型就被拒之門外了(編譯報(bào)錯(cuò))。并且由于C++標(biāo)準(zhǔn)中,sizeof()的操作數(shù)不會(huì)被求值,所以我們無需定義static_array_size_fn()函數(shù)體,從而上述設(shè)施完全是零代價(jià)的。沒有任何運(yùn)行時(shí)開銷,也不會(huì)導(dǎo)致代碼膨脹。

 

讓我們回到“C/C++數(shù)組在被傳遞給函數(shù)時(shí)會(huì)退化成指針”的問題上來,如果我們?cè)诂F(xiàn)實(shí)中需要將一個(gè)將任意長(zhǎng)度的數(shù)組傳遞給一個(gè)期望接受數(shù)組的函數(shù),那么該怎么辦呢?困惑的實(shí)質(zhì)在于數(shù)組的大小在傳遞過程中丟失了,因此,如果我們可以找到一種將數(shù)組大小隨之傳遞給函數(shù)的機(jī)制,問題就會(huì)迎刃而解。有了上面宏定義的經(jīng)驗(yàn),通過模板我們找到一個(gè)解決方案:

template<typename T>
class array_proxy
{
public:
    typedef T               value_type;
    typedef array_proxy<T>  class_type;
    typedef value_type *    pointer;
    typedef value_type *    const_pointer;      // Non-const!
    typedef value_type &    reference;
    typedef value_type &    const_reference;    // Non-const!
    typedef size_t          size_type;
// 構(gòu)造函數(shù)
public:
    template<size_t N>
    explicit array_proxy(T(&t)[N])    // 元素類型為T的數(shù)組
        : m_begin(&t[0])
        , m_end(&t[N])
    {}
    template<typename D, size_t N>
    explicit array_proxy(D(&d)[N])    // 元素類型為T兼容類型的數(shù)組
        : m_begin(&d[0])
        , m_end(&d[N])
    {
        constraint_must_be_same_size(T, D);    // 確保D和T大小相同
    }
    template<typename D>
    array_proxy(array_proxy<D> &d)
        : m_begin(d.begin())
        , m_end(d.end())
    {
        constraint_must_be_same_size(T, D);    // 確保D和T大小相同
    }
// 狀態(tài)
public:
    pointer             base();
    const_pointer       base() const;
    size_type           size() const;
    bool                empty() const;
    static size_type    max_size();
// 下標(biāo)索引操作符
public:
    reference        operator [](size_t index);
    const_reference  operator [](size_t index) const;
// 迭代操作
public:
    pointer          begin();
    const_pointer    begin() const;
    pointer          end();
    const_pointer    end() const;
// 數(shù)據(jù)成員
private:
    pointer const m_begin;
    pointer const m_end;
// 聲明但不予實(shí)現(xiàn)
private:
    array_proxy & operator =(array_proxy const &);
};
 
// 轉(zhuǎn)發(fā)函數(shù)
template<typename T, size_t N>
inline array_proxy<T> make_array_proxy(T(&t)[N])
{
    return array_proxy<T>(t);
}
template<typename T>
inline array_proxy<T> make_array_proxy(T * base, size_t size)
{
    return array_proxy<T>(base, size);
}

客戶代碼修改為:

void process_array(const array_proxy<int> & ar)
{
    std::copy(ar.begin(), ar.end(), ostream_iterator<int>(cout, " "));
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    int ar[5] = {0, 1, 2, 3, 4};
    
    process_array(make_array_proxy(ar));
 
    return 0;
}

我們的問題終于有了一個(gè)徹底的解決方案。該解決方案是高效的(在任何一個(gè)說得過去的編譯器上它都沒有任何額外的開銷),是類型安全的,并且完全使得函數(shù)的設(shè)計(jì)者能夠防止?jié)撛诘恼`用(更確切的說,讓代碼能夠更強(qiáng)的抵御派生類數(shù)組的誤用)。此外,它還足夠智能,允許派生類跟父類具有相同大小的情況下,它們的數(shù)組被“代理”。

最后一個(gè)優(yōu)點(diǎn)是現(xiàn)在再也不可能將錯(cuò)誤的數(shù)組長(zhǎng)度傳給被調(diào)函數(shù)了,以前我們慣用的使用兩個(gè)參數(shù)(一個(gè)傳遞數(shù)組指針,一個(gè)傳遞數(shù)組長(zhǎng)度)的函數(shù)版本中誤傳長(zhǎng)度的危險(xiǎn)是時(shí)時(shí)存在的。這個(gè)優(yōu)勢(shì)使我們得以遵從DRY(Don't Repeat Yourself!)原則。

 

NULL宏

在C語言中,void*類型可以被隱式地轉(zhuǎn)換為其他任何指針類型,所以我們可以將NULL定義為((void*)0),從而跟其他任何指針類型間實(shí)現(xiàn)互相轉(zhuǎn)換。然而,C++不允許從void*到任何指針的隱式轉(zhuǎn)換,又因?yàn)镃++中0可以被轉(zhuǎn)換為任何指針類型,因此,C++標(biāo)準(zhǔn)規(guī)定:NULL宏是一個(gè)由實(shí)現(xiàn)定義的C++空指針常量....其可能的定義方式包括0和0L,但絕對(duì)不是(void*)0。

由于0不可置疑的可以轉(zhuǎn)換成任何整型,甚至wchar_t和bool,以及浮點(diǎn)類型,這就意味著,使用NULL的時(shí)候,類型檢查將不再發(fā)生,我們很容易毫無察覺的走向厄運(yùn)的深淵,連個(gè)警告都沒有。考慮如下情況:

// 自定義的字符串類
//
class String
{
    explicit String(char const *s);                  // 接受外界傳入的空指針
    explicit String(int cch, char chInit = '\0');    // 根據(jù)可能被使用的字符數(shù)估計(jì),來初始化底層存儲(chǔ)
};

現(xiàn)在當(dāng)我們用NULL做參數(shù)構(gòu)造String時(shí),第二個(gè)構(gòu)造函數(shù)會(huì)被調(diào)用!也許和你的初衷不同,編譯器卻會(huì)一聲不吭的編譯通過。這可不妙。如果你將int改為size_t(或short、或long、或任何不是int的內(nèi)建類型),編譯器將會(huì)在兩個(gè)轉(zhuǎn)換之間左右為難,結(jié)果是得到一個(gè)二義性錯(cuò)誤。

 

我們想要個(gè)完善的空指針關(guān)鍵字!很快作者想出了辦法,你不應(yīng)該感到驚訝,解決方案離不開模板:

struct NULL_v
{
// 構(gòu)造函數(shù)
public:
    NULL_v()
    {}
// 轉(zhuǎn)換操作符
public:
    template<typename T>
    operator T* () const
    {
        return 0;
    }
    template<typename T2, typename C>
    operator T2 C::*() const
    {
        return 0;
    }
    template<typename T>
    bool equals(T const & rhs) const
    {
        return rhs == 0;
    }
// 聲明但不予實(shí)現(xiàn)
private:
    void operator &() const;    // Scott: 純粹是值的東西的地址是沒有任何意義的。
    NULL_v(NULL_v const &);
    NULL_v& operator =(NULL_v const &);
};
 
template<typename T>
inline bool operator ==(NULL_v const & lhs, T const & rhs)
{
    return lhs.equals(rhs);
}
 
template<typename T>
inline bool operator ==(T const & lhs, NULL_v const & rhs)
{
    return rhs.equals(lhs);
}
 
template<typename T>
inline bool operator !=(NULL_v const & lhs, T const & rhs)
{
    return !lhs.equals(rhs);
}
 
template<typename T>
inline bool operator !=(T const & lhs, NULL_v const & rhs)
{
    return !rhs.equals(lhs);
}
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            一区二区三区av| 亚洲一区日韩| 亚洲精品乱码久久久久久蜜桃91| 亚洲一卡二卡三卡四卡五卡| 免费黄网站欧美| 午夜国产精品视频| 欧美性生交xxxxx久久久| 亚洲韩国日本中文字幕| 久久精品国产2020观看福利| 国产欧美日韩中文字幕在线| 亚洲欧洲精品一区二区三区不卡| 欧美中文字幕在线观看| 在线亚洲电影| 欧美视频中文在线看| 亚洲人成人77777线观看| 久久精品在这里| 久久成人国产精品| 亚洲欧美精品在线观看| 女女同性精品视频| 亚洲第一天堂无码专区| 另类专区欧美制服同性| 久久久精品国产一区二区三区 | 亚洲校园激情| 亚洲日本久久| 欧美精品亚洲精品| 99精品国产在热久久| 亚洲精品久久久久| 欧美日韩综合在线| 午夜一区不卡| 亚洲尤物视频在线| 国产一区二区三区免费不卡| 久久婷婷综合激情| 久久综合999| 日韩午夜剧场| 亚洲视频精选| 国产一区二区av| 男人的天堂成人在线| 欧美国产视频在线观看| 亚洲一区二区三区精品在线观看 | 国产精品色婷婷| 欧美中文字幕精品| 久久全国免费视频| 99国产麻豆精品| 亚洲综合日韩在线| 亚洲第一福利视频| 亚洲精品一区二区三区蜜桃久| 欧美午夜精品久久久久久浪潮 | 欧美不卡视频一区发布| 欧美激情精品| 欧美专区在线| 欧美成人在线影院| 久久大逼视频| 欧美激情中文字幕一区二区| 新片速递亚洲合集欧美合集| 久久女同精品一区二区| 亚洲一区二区三区成人在线视频精品| 亚洲欧美大片| 亚洲国产精品一区二区久| 一区二区三区精品| 在线看欧美视频| 欧美日韩ab片| 欧美一区二区视频在线| 久久阴道视频| 欧美亚洲网站| 欧美激情黄色片| 久久久久一区二区三区| 欧美日韩日日骚| 可以看av的网站久久看| 国产精品国产精品| 亚洲狼人精品一区二区三区| 在线播放国产一区中文字幕剧情欧美| av成人免费在线观看| 亚洲国产日日夜夜| 欧美一二区视频| 在线亚洲自拍| 欧美成人在线免费观看| 久热精品视频在线观看| 国产老肥熟一区二区三区| 亚洲人在线视频| 亚洲国产一区二区三区在线播| 先锋影音网一区二区| 亚洲一区二区综合| 欧美伦理影院| 亚洲激情电影中文字幕| 亚洲电影在线播放| 久久精品亚洲精品| 欧美在线免费观看视频| 国产精品美女一区二区在线观看| 91久久国产自产拍夜夜嗨| 有码中文亚洲精品| 久久精品免费| 久久久久国内| 国内精品久久久久影院优| 欧美一区二区三区视频| 久久久久久**毛片大全| 国产亚洲一区二区三区| 午夜在线a亚洲v天堂网2018| 香蕉精品999视频一区二区| 欧美视频一区二区三区四区| 夜夜嗨av一区二区三区四季av| 一本久道久久综合婷婷鲸鱼| 欧美女同在线视频| 日韩午夜在线视频| 亚洲男人的天堂在线| 欧美先锋影音| 亚洲在线成人| 欧美诱惑福利视频| 国产又爽又黄的激情精品视频| 久久精品动漫| 亚洲第一主播视频| 一区二区国产日产| 国产精品www网站| 亚洲免费网址| 久久午夜精品| 91久久一区二区| 欧美日韩成人网| 亚洲天堂男人| 久久先锋影音| 亚洲精品国产视频| 欧美日韩国产另类不卡| 亚洲一二三区精品| 久久在线免费观看视频| 亚洲精品免费一二三区| 欧美午夜精品一区| 欧美在线播放| 亚洲欧洲精品一区二区三区| 一本久久a久久免费精品不卡| 国产精品xnxxcom| 亚洲欧美影音先锋| 亚洲一区二区三区精品在线观看| 欧美日韩免费网站| 欧美视频一区二区三区在线观看| 国产欧美一区二区三区在线看蜜臀| 激情一区二区| 欧美一区二区观看视频| 亚洲精品日韩久久| 美女诱惑一区| 影音先锋一区| 毛片av中文字幕一区二区| 久久亚洲一区| 亚洲视频在线一区观看| 国产日韩精品视频一区| 久久婷婷麻豆| 中文在线一区| 欧美多人爱爱视频网站| 午夜免费电影一区在线观看| 亚洲国产91| 国产精品乱码一区二三区小蝌蚪 | 亚洲一级黄色av| 韩国欧美一区| 欧美日韩一区在线观看视频| 久久久九九九九| 亚洲一区二区三区免费视频| 亚洲高清三级视频| 久久久水蜜桃| 亚洲欧美日韩一区在线观看| 亚洲区一区二区三区| 韩国免费一区| 国产一区999| 国产日产亚洲精品系列| 欧美性做爰毛片| 欧美黄色网络| 美女视频黄 久久| 久久蜜臀精品av| 欧美一区高清| 亚洲午夜在线观看| 亚洲乱码久久| 亚洲欧洲在线看| 亚洲国产一区二区三区青草影视| 久久精品视频在线看| 欧美一级播放| 西瓜成人精品人成网站| 亚洲一区中文| 亚洲制服欧美中文字幕中文字幕| 日韩视频免费观看| 亚洲人成人一区二区三区| 在线观看视频免费一区二区三区| 国产乱肥老妇国产一区二| 国产精品美女www爽爽爽| 欧美吻胸吃奶大尺度电影| 欧美日韩亚洲视频| 欧美区二区三区| 欧美成人高清| 欧美欧美午夜aⅴ在线观看| 欧美成人精品一区| 欧美极品在线播放| 欧美区日韩区| 欧美三日本三级少妇三2023| 欧美三日本三级三级在线播放| 欧美日一区二区在线观看 | 欧美日韩国产精品成人| 久久久久九九九| 99国产麻豆精品| 国产网站欧美日韩免费精品在线观看 | 久久久久久午夜| 亚洲精选一区| 黄色亚洲在线| 国产日韩精品一区| 欧美私人啪啪vps| 欧美日韩视频免费播放|