Boost optional 詳解

optional庫使用"容器"語義杜顺,包裝了"可能產(chǎn)生無效值"的對(duì)象饺饭,實(shí)現(xiàn)了"未初始化"的概念物喷。

#include <boost/optional.hpp>
using namespace boost;

"無意義"的值:

函數(shù)并不總能返回有效的返回值惯悠,很多時(shí)候函數(shù)可能返回"無意義"的值邻邮,這不意味著函數(shù)執(zhí)行失敗,而是表明函數(shù)正確執(zhí)行了克婶,但結(jié)果卻不是有用的值饶囚。

表示返回值無意義最常用的做法是增加一個(gè)"哨兵"的角色,它位于解空間之外鸠补,如NULL萝风,-1,EOF紫岩,string::npos,vector::end()等规惰。但這些做法不夠通用,而且很多時(shí)候不存在解空間之外的"哨兵"泉蝌。

optional使用"容器"語義歇万,為這種"無效值"的情形提供了一個(gè)較好的解決方案。

optional很像一個(gè)僅能存放一個(gè)元素的容器勋陪,它實(shí)現(xiàn)了"未初始化"的概念:如果元素未初始化贪磺,那么容器就是空的,否則诅愚,容器內(nèi)就是有效的寒锚,已經(jīng)初始化的值。

optional的真實(shí)接口很復(fù)雜违孝,因?yàn)樗軌虬b任何的類型刹前。

操作函數(shù)

optional的模板類型參數(shù)T可以使任何類型,就如同一個(gè)標(biāo)準(zhǔn)容器對(duì)元素的要求雌桑,并不需要T具有缺省構(gòu)造函數(shù)喇喉,但必須是可拷貝構(gòu)造的。

可以有很多方式創(chuàng)建optional對(duì)象校坑,例如:

  • 無參的optional()或者optional(boost::none)構(gòu)造一個(gè)未初始化optional對(duì)象拣技,參數(shù)boost::none是一個(gè)類似空指針的none_t類型常量千诬,表示未初始化。
  • optional(v)構(gòu)造一個(gè)已初始化的optional對(duì)象膏斤,其值為v的拷貝徐绑。如果模板類型為T&,那么optional內(nèi)部持有對(duì)引用的包裝掸绞。
  • optional(condition, v)根據(jù)條件condition來構(gòu)造optional對(duì)象,如果條件成立(true)則初始化為v耕捞,否則為未初始化衔掸。
  • 此外optional還支持拷貝構(gòu)造和賦值操作,可以從另一個(gè)optional對(duì)象構(gòu)造俺抽。當(dāng)想讓一個(gè)optional對(duì)象重新恢復(fù)到未初始化狀態(tài)時(shí)敞映,可以向?qū)ο筚xnone值。

optional采用了指針語義來訪問內(nèi)部保存的元素磷斧,這使得optional未初始化時(shí)的行為就像一個(gè)空指針振愿。它重載了operator*和operator->以實(shí)現(xiàn)與指針相同的操作,get()和get_ptr()可以以函數(shù)的操作形式獲得元素的引用和指針弛饭。

成員函數(shù)get_value_or(default)是一個(gè)特別的訪問函數(shù)冕末,可以保證返回一個(gè)有效的值,如果optional已初始化侣颂,那么返回內(nèi)部的元素档桃,否則返回default。

optional也可以用隱式類型轉(zhuǎn)換進(jìn)行bool測(cè)試(用于條件判斷),就像一個(gè)隊(duì)指針的判斷憔晒。

optional還全面支持比較運(yùn)算藻肄,包括==,!=,<,<,>,>=拒担。與普通指針比較的"淺比較"(僅比較指針值)不同嘹屯,optional的比較是"深比較",同時(shí)加入了對(duì)未初始化情況的判斷从撼。

用法

optional的接口簡單明了州弟,把它認(rèn)為是一個(gè)大小為1并且行為類似指針的容器就可以了,或者把它想象成是一個(gè)類似scoped_ptr, shared_ptr的智能指針(注意低零,optional不是智能指針呆馁,用法類似但用途不同)。

代碼示范1:

#include <boost/optional.hpp>
using namespace boost;
using namespace std;
int main()
{
     optional<int> op0;                    //一個(gè)未初始化的optional對(duì)象
     optional<int> op1(boost::none);       //同上毁兆,使用none賦予未初始化值
     assert(!op0);
     assert(op0 == op1);
     assert(op1.get_value_or(253) == 253); //獲取可選值

     optional<string> ops("test");         //初始化為字符串test
     string str = *ops;                    //用解引用操作符獲取值
     cout <<str.c_str()<<endl;

     vector<int> v(10);
     optional<vector<int>&> opv(v);        //容納一個(gè)容器的引用
     assert(opv);

     opv->push_back(5);                    //使用箭頭操作符操縱容器
     assert(opv->size() == 11);
     opv = boost::none;
     assert(!opv);
     system("pause");
     return 0;
}

代碼示范2:

#include <math.h>
#include <boost/optional.hpp>
using namespace boost;
using namespace std;
optional<double> calc(int x)    //計(jì)算倒數(shù)
{
    return optional<double>(x != 0, 1.0 / x);//條件構(gòu)造函數(shù)
}
optional<double> sqrt_op(double x)   //計(jì)算實(shí)數(shù)的平方根
{
    return optional<double>(x>0, sqrt(x));//條件構(gòu)造函數(shù)
}
int main()
{
    optional<double> d = calc(10);
    if (d)
        cout << *d <<endl;
    d = sqrt_op(-10);
    if (!d)
        cout << "no result"<<endl;

    system("pause");
    return 0;
}

工廠函數(shù):

optional提供一個(gè)類似make_pair(),make_shared()的工廠函數(shù)make_optional(),可以根據(jù)參數(shù)類型自動(dòng)推導(dǎo)optional的類型浙滤,用來輔助創(chuàng)建optional對(duì)象,聲明:

optional<T> make_optional(T const &v);
optional<T> make_optional(bool condition, T const& v);

tips: 但make_optional()無法推導(dǎo)出T引用類型的optional對(duì)象气堕,因此如果需要一個(gè)optional<T&>的對(duì)象纺腊,就不能使用make_optional()函數(shù)畔咧。

代碼示例:

#include <boost/optional.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
int main()
{
    BOOST_AUTO(x, make_optional(5));
    assert(*x == 5);


    BOOST_AUTO(y, make_optional<double>((*x > 10), 1.0));
    assert(!y);
    
    system("pause");
    return 0;
}

高級(jí)議題

異常處理

optional<T>同STL容器一樣,只提供基本的異常保證揖膜,不會(huì)超過被包裝的類型T誓沸,它自身不拋出任何異常,只有在T構(gòu)造時(shí)可能會(huì)拋出異常壹粟。

就地創(chuàng)建

optional<T>要求類型T具有拷貝語義拜隧,因?yàn)樗鼉?nèi)部會(huì)保存值的拷貝,但很多時(shí)候復(fù)雜對(duì)象的拷貝代價(jià)很高趁仙,而且這個(gè)值僅僅作為拷貝的臨時(shí)用途洪添,是一種浪費(fèi)。

因此optional庫提供出了"就地創(chuàng)建"的概念雀费,可以不要求類型具有拷貝語義干奢,直接用構(gòu)造函數(shù)所需的參數(shù)創(chuàng)建對(duì)象,這導(dǎo)致發(fā)展處了另一個(gè)Boost庫in_place_factory盏袄。

代理示例:

#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
using namespace boost;
using namespace std;

int main()
{
    //就地創(chuàng)建string對(duì)象忿峻,不需要臨時(shí)對(duì)象string("..")
    optional<string> ops(in_place("test in_place_factory"));
    cout<< (*ops).c_str()<<endl;
    
    //就地創(chuàng)建std::vector對(duì)象,不需要臨時(shí)對(duì)象vector(10, 3)
    optional<vector<int>> opp(in_place(10, 3));
    assert(opp->size() == 10);
    assert((*opp)[0] == 3);

    system("pause");
    return 0;
}
引用類型

optional的模板參數(shù)類型可以使用引用(T&),它在很多方面與原始類型T有不同辕羽,比如無法使用就地創(chuàng)建逛尚,就地賦值。與c++語言內(nèi)置的引用類型不同的是刁愿,它可以聲明時(shí)不指定初值黑低,并且在賦值時(shí)轉(zhuǎn)移包裝的對(duì)象,而不是對(duì)原包裝的對(duì)象賦值酌毡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末克握,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子枷踏,更是在濱河造成了極大的恐慌菩暗,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旭蠕,死亡現(xiàn)場(chǎng)離奇詭異停团,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掏熬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門佑稠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旗芬,你說我怎么就攤上這事舌胶。” “怎么了疮丛?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵幔嫂,是天一觀的道長辆它。 經(jīng)常有香客問我,道長履恩,這世上最難降的妖魔是什么锰茉? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮切心,結(jié)果婚禮上飒筑,老公的妹妹穿的比我還像新娘。我一直安慰自己绽昏,他們只是感情好协屡,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著而涉,像睡著了一般著瓶。 火紅的嫁衣襯著肌膚如雪联予。 梳的紋絲不亂的頭發(fā)上啼县,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音沸久,去河邊找鬼季眷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卷胯,可吹牛的內(nèi)容都是我干的子刮。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼窑睁,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挺峡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起担钮,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤橱赠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箫津,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狭姨,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年苏遥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饼拍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡田炭,死狀恐怖师抄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情教硫,我是刑警寧澤司澎,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布欺缘,位于F島的核電站,受9級(jí)特大地震影響挤安,放射性物質(zhì)發(fā)生泄漏谚殊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一蛤铜、第九天 我趴在偏房一處隱蔽的房頂上張望嫩絮。 院中可真熱鬧,春花似錦围肥、人聲如沸剿干。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽置尔。三九已至,卻和暖如春氢伟,著一層夾襖步出監(jiān)牢的瞬間榜轿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國打工朵锣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谬盐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓诚些,卻偏偏與公主長得像飞傀,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诬烹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • 多線程砸烦、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景绞吁。SDWebImage的原...
    LZM輪回閱讀 2,009評(píng)論 0 12
  • 1.Timer.1 - 使用同步定時(shí)器 先完整介紹一下幢痘,后面的例子該省略的就省略了。所有的Asio類只要簡單的包含...
    Otis4631閱讀 6,533評(píng)論 0 0
  • 1. 概述 C++沒有提供類似JAVA的垃圾回收機(jī)制掀泳,所以對(duì)象不會(huì)在不使用時(shí)自動(dòng)銷毀雪隧。盡管STL提供了 std::...
    戴廿叁閱讀 1,088評(píng)論 0 0
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,836評(píng)論 0 38
  • 久違的晴天,家長會(huì)员舵。 家長大會(huì)開好到教室時(shí)脑沿,離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)马僻。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,528評(píng)論 16 22