Effective Modern C++ - 3: 步入 Modern C++

item8 nullptr 優(yōu)先于 0 和 NULL

總結(jié):

(1) 0: 0 是 int 型, 編譯器將 應(yīng)該出現(xiàn)指針卻出現(xiàn)0的位置上的0 勉強(qiáng)轉(zhuǎn)換為 空指針 (void*)0

(2) NULL: C++ 中可能被編譯器底層實現(xiàn)為 整型 (int/long)

Note: C 中, 還可能被編譯器底層實現(xiàn)為空指針 (void*)0

(3) nullptr: 可 隱式轉(zhuǎn)換所有/任意類型裸指針類型(進(jìn)而可以被 智能指針形參 接收: 構(gòu)造出 智能指針), 不會被視為任何整型

nullptr 的類型是 std::nullptr_t

std::nullptr_t 可隱式轉(zhuǎn)換為 all pointer types

分析: 相對于 0/NULL,

1 nullptr 可避免 重載解析時的混淆/錯誤

0/NULL 作實參, 調(diào)重載函數(shù) f(int/bool/void*) 時, 必然調(diào)用 f(int), 而非 f(void*) / 行為不確定

原因: 若 NULL 實現(xiàn)為 0L, 0L(long) -> int/bool/void*被編譯器認(rèn)為同樣好

void f(int); // three overloads of f
void f(bool);
void f(void*);

f(0);       // calls f(int), not f(void*)

f(NULL);    // might not compile, but typically calls
            // f(int). Never calls f(void*)

f(nullptr); // calls f(void*) overload

2 nulptr 提高了代碼的 清晰性, 尤其與 auto 結(jié)合時

(1) 用 0 看不出 函數(shù)的返回類型

auto result = findRecord( /* arguments */ );
if (result == 0) 
{
    …
}

(2) 用 0 能看出函數(shù)的返回類型必然為指針類型

auto result = findRecord( /* arguments */ );
if (result == nullptr) 
{
    …
}

3 nullptr 在模板中優(yōu)勢最大

lock + call

int f1(std::shared_ptr<Widget> spw);    // call these only when
double f2(std::unique_ptr<Widget> upw); // the appropriate
bool f3(Widget* pw);                    // mutex is locked
std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
using MuxGuard = std::lock_guard<std::mutex>;
…
{
    MuxGuard g(f1m);        // lock mutex for f1
    auto result = f1(0);    // pass 0 as null ptr to f1
} // unlock mutex
…

{
    MuxGuard g(f2m);        // lock mutex for f2
    auto result = f2(NULL); // pass NULL as null ptr to f2
} // unlock mutex
…

{
    MuxGuard g(f3m);            // lock mutex for f3
    auto result = f3(nullptr);  // pass nullptr as null ptr to f3
} // unlock mutex

前2個沒用 nullptr, 但也正確

Extract 1個模板來去重, 將 指針實參 抽象為 指針類型 PtrType => 0/NULL 作實參 推斷出錯誤的類型 int/int 或 long, int/int 或 long 再試圖傳給 智能指針型形參的函數(shù) f1/f2 時, 類型錯誤, 編譯報錯

nullptr 的類型是 std::nullptr_t => PtrType 為 std::nullptr_t, 再傳給 f3時, std::nullptr_t 隱式轉(zhuǎn)換為 Widget*

template<typename FuncType,
        typename MuxType,
        typename PtrType>
    auto 
lockAndCall(FuncType func,
            MuxType& mutex, // mutex 以引用傳遞
            PtrType ptr) -> decltype( func(ptr) )
{
    MuxGuard g(mutex);
    return func(ptr);
}
auto result1 = lockAndCall(f1, f1m, 0); // error!
…
auto result2 = lockAndCall(f2, f2m, NULL); // error!
…
auto result3 = lockAndCall(f3, f3m, nullptr); // fine

解決: 1/2用 nullptr 調(diào)用

例1: 0/NULL 能直接傳給 智能指針: 先隱式轉(zhuǎn)換為空指針, 再構(gòu)造出智能指針

#include <mutex>
#include <memory>

class Widget
{
};

int f1(std::shared_ptr<Widget> spw)     // call these only when
{
    return 0;
}
double f2(std::unique_ptr<Widget> upw) // the appropriate
{
    return 0.0;
}

bool f3(Widget* pw)                     // mutex is locked
{
    return false;
}

int main()
{
    std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
    using MuxGuard = std::lock_guard<std::mutex>;

    {
        MuxGuard g(f1m);        // lock mutex for f1
        auto result = f1(0);    // pass 0 as null ptr to f1
    } // unlock mutex

    {
        MuxGuard g(f2m);        // lock mutex for f2
        auto result = f2(NULL); // pass NULL as null ptr to f2
    } // unlock mutex

    {
        MuxGuard g(f3m);            // lock mutex for f3
        auto result = f3(nullptr);  // pass nullptr as null ptr to f3
    } // unlock mutex
}

例2: 0/NULL 不能 通過 1次模板實參推斷后, 再通過隱式轉(zhuǎn)換為空指針而間接傳給智能指針

原因: 函數(shù)模板實例化過程中, 函數(shù)模板實參推斷后, 只能按推斷出的類型傳遞給另一函數(shù), 不再進(jìn)行隱式轉(zhuǎn)換

#include <mutex>
#include <memory>

class Widget
{
};

int f1(std::shared_ptr<Widget> spw)     // call these only when
{
    return 0;
}
double f2(std::unique_ptr<Widget> upw) // the appropriate
{
    return 0.0;
}

bool f3(Widget* pw)                     // mutex is locked
{
    return false;
}

using MuxGuard = std::lock_guard<std::mutex>;

template<typename FuncType,
    typename MuxType,
    typename PtrType>
    auto
lockAndCall(FuncType func,
        MuxType& mutex, // mutex 以引用傳遞
        PtrType ptr) -> decltype(func(ptr))
{
    MuxGuard g(mutex);
    return func(ptr);
}

int main()
{
    std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3

    auto result1 = lockAndCall(f1, f1m, 0);         // error!
    auto result2 = lockAndCall(f2, f2m, NULL);      // error!
    auto result3 = lockAndCall(f3, f3m, nullptr);   // fine
}
#include <mutex>
#include <memory>

class Widget
{
};

int f1(std::shared_ptr<Widget> spw)     // call these only when
{
    return 0;
}
double f2(std::unique_ptr<Widget> upw) // the appropriate
{
    return 0.0;
}

bool f3(Widget* pw)                     // mutex is locked
{
    return false;
}

using MuxGuard = std::lock_guard<std::mutex>;

template<typename FuncType,
    typename MuxType,
    typename PtrType>
    auto
lockAndCall(FuncType func,
        MuxType& mutex, // mutex 以引用傳遞
        PtrType ptr) -> decltype(func(ptr))
{
    MuxGuard g(mutex);
    return func(ptr);
}

int main()
{
    std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3

    auto result1 = lockAndCall(f1, f1m, nullptr);   // fine
    auto result2 = lockAndCall(f2, f2m, nullptr);   // fine
    auto result3 = lockAndCall(f3, f3m, nullptr);   // fine
}

item15 只要可能就用 constexpr: 編譯期計算 / 運行期計算(不能進(jìn)行編譯期計算時, 自動降級為 運行期計算)

1 用于對象

constexpr auto arraySize2 = 10;     // fine, 10 is a

std::array<int, arraySize2> data2;  // fine, arraySize2
                                    // is constexpr

2 用于非成員函數(shù)

constexpr            // pow's a constexpr func
int pow(int base, int exp) noexcept // that never throws, base^exp
{
    return (exp == 0 ? 1 : base * pow(base, exp - 1) ); // C++11: 只支持函數(shù)體含1行語句, 可以是遞歸
}
constexpr int 
pow(int base, int exp) noexcept // C++14: 支持函數(shù)體含多行語句
{
    auto result = 1;
    for (int i = 0; i < exp; ++i) 
        result *= base;
    return result;
}

(1) 編譯期值作實參 調(diào)用, 返回 編譯期結(jié)果

constexpr auto numConds = 5; // # of conditions

std::array<int, pow(3, numConds)> results;  // results has
                                            // 3^numConds
                                            // elements

(2) 運行期值作實參 調(diào)用, 返回 運行期結(jié)果

auto base = readFromDB("base");     // get these values
auto exp = readFromDB("exponent");  // at runtime
auto baseToExp = pow(base, exp);    // call pow function
                                    // at runtime

3 用于成員函數(shù): 運行期構(gòu)造 + 調(diào)成員函數(shù)

class Point {
public:
    constexpr Point(double xVal = 0, double yVal = 0) noexcept
        : x(xVal), y(yVal) {}
        
    constexpr double xValue() const noexcept { return x; }
    constexpr double yValue() const noexcept { return y; }
    
    void setX(double newX) noexcept { x = newX; }
    void setY(double newY) noexcept { y = newY; }
private:
    double x, y;
};
constexpr Point p1(9.4, 27.7);  // fine, "runs" constexpr
                                // ctor during compilation

constexpr Point p2(28.8, 5.3);  // also fine

constexpr
Point midpoint(const Point& p1, const Point& p2) noexcept
{
    return { (p1.xValue() + p2.xValue()) / 2,   
             (p1.yValue() + p2.yValue()) / 2 }; // call constexpr member funcs
}

constexpr auto mid = midpoint(p1, p2);  // init constexpr
                                        // object w/result of
                                        // constexpr function

item16 使 const 成員函數(shù) 線程安全

原因: const 成員函數(shù)修改 mutable 成員(如 cache + cacheIsValid) + 多線程 -> not 線程安全

remember

(1) 確保 const 成員函數(shù)線程安全, 除非你確定不會在并發(fā) context 中使用

(2) std::atomic 變量可能比 mutex 性能高, 但只適用于操作單個 變量或內(nèi)存位置

class Polynomial 
{
public:
    using RootsType = std::vector<double>;
    
    RootsType 
    roots() const
    {
        std::lock_guard<std::mutex> g(m); // lock mutex
        
        if (!rootsAreValid)         // if cache not valid
        {       
            …                       // compute, 
                                    // store them in rootVals
            rootsAreValid = true;
        }
        return rootVals;
    }
private:
    mutable std::mutex m;
    mutable bool rootsAreValid{ false }; // see Item 7 for initializers
    mutable RootsType rootVals{};       
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載丹锹,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者结序。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市矗晃,隨后出現(xiàn)的幾起案子谴供,更是在濱河造成了極大的恐慌,老刑警劉巖描函,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件季二,死亡現(xiàn)場離奇詭異,居然都是意外死亡拒啰,警方通過查閱死者的電腦和手機(jī)驯绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谋旦,“玉大人剩失,你說我怎么就攤上這事〔嶙牛” “怎么了拴孤?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長甲捏。 經(jīng)常有香客問我演熟,道長,這世上最難降的妖魔是什么司顿? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任芒粹,我火速辦了婚禮,結(jié)果婚禮上大溜,老公的妹妹穿的比我還像新娘化漆。我一直安慰自己,他們只是感情好钦奋,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布座云。 她就那樣靜靜地躺著,像睡著了一般付材。 火紅的嫁衣襯著肌膚如雪朦拖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天厌衔,我揣著相機(jī)與錄音贞谓,去河邊找鬼。 笑死葵诈,一個胖子當(dāng)著我的面吹牛裸弦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播作喘,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼理疙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泞坦?” 一聲冷哼從身側(cè)響起窖贤,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贰锁,沒想到半個月后赃梧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡豌熄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年授嘀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锣险。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹄皱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芯肤,到底是詐尸還是另有隱情巷折,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布崖咨,位于F島的核電站锻拘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏击蹲。R本人自食惡果不足惜署拟,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望际邻。 院中可真熱鬧芯丧,春花似錦、人聲如沸世曾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轮听。三九已至骗露,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間血巍,已是汗流浹背萧锉。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留述寡,地道東北人柿隙。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓叶洞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親禀崖。 傳聞我的和親對象是個殘疾皇子衩辟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 Google Play應(yīng)用市場對于應(yīng)用的targetSdkVersion有了更為嚴(yán)格的要求。從 2018 年...
    申國駿閱讀 63,937評論 14 98
  • 《來,我們說說孤獨》 1·他們都在寫孤獨 一個詩人 如果 不說說 內(nèi)心的孤獨 不將孤獨 寫進(jìn)詩里 是不是很掉價呢 ...
    聽太陽升起閱讀 4,370評論 1 7
  • 自幼貧民窟長大的女子掸屡,僥幸多念了兩本書封寞,枉以為可以與人平起平坐〗霾疲可是人生從來都是接力賽狈究,我們卻天真的當(dāng)成了百米沖刺...
    Leeanran閱讀 5,762評論 1 5
  • 云舒老師,姓甚名誰满着,男的女的谦炒,多大歲數(shù),這些我全然不知风喇。之所以要寫寫云舒老師宁改,完全是因為他寫的文章,如一個巨大的磁...
    數(shù)豆者m閱讀 2,334評論 5 9
  • """1.個性化消息: 將用戶的姓名存到一個變量中魂莫,并向該用戶顯示一條消息还蹲。顯示的消息應(yīng)非常簡單,如“Hello ...
    她即我命閱讀 2,862評論 0 5