• <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>

            我的第一本C++書(shū)

            游歷C++世界的地圖

            置頂隨筆 #

            [置頂]《我的第一本C++書(shū)》,你值得擁有


             

            作為一本入門級(jí)的C++書(shū),本書(shū)在創(chuàng)作的時(shí)候堅(jiān)持這樣三個(gè)原則:

            • 內(nèi)容翔實(shí),堅(jiān)持以實(shí)用為主,介紹了C++中最常用的必須掌握的絕大部分知識(shí),對(duì)于一些很少用到的語(yǔ)法知識(shí),則較少涉及。在講解的時(shí)候,也以實(shí)際的應(yīng)用場(chǎng)景為主,避免孔乙己式的深究C++的語(yǔ)法細(xì)節(jié)。
            • 語(yǔ)言生動(dòng)有趣,避免以往教科書(shū)式的呆板面孔。全書(shū)以一個(gè)C++世界為主線,形象生動(dòng)地介紹了C++世界中的各種食物。全書(shū)中豐富的比喻,可以讓讀者對(duì)比較抽象難懂的C++知識(shí)有一個(gè)形象的劣跡,更利于掌握知識(shí)。
            • 堅(jiān)持理論實(shí)踐相結(jié)合。在講解知識(shí)的同時(shí),結(jié)合作者自己多年的實(shí)踐經(jīng)驗(yàn),提醒讀者這些C++知識(shí)應(yīng)該如何應(yīng)用,在應(yīng)用的過(guò)程中需要注意些什么,同時(shí)有大量的實(shí)例加以示范,這樣可以避免讀者掌握了C++的語(yǔ)法知識(shí),卻沒(méi)法動(dòng)手寫(xiě)程序的紙上談兵式的學(xué)習(xí)。特別是最后一章收集整理的各大公司的鄙視題目與分析,對(duì)讀者有很大的實(shí)用價(jià)值。

            如果你是一個(gè)C++新手,正在尋找一本C++的入門書(shū),這本書(shū)就是你的最佳選擇。這本書(shū)從零起步,不僅循序漸進(jìn)地介紹了C++的知識(shí),更介紹了如何應(yīng)用這些知識(shí)來(lái)開(kāi)發(fā)程序。生動(dòng)有趣的語(yǔ)言,讓C++那些枯燥的知識(shí)也生動(dòng)活潑起來(lái),學(xué)習(xí)不再是一件枯燥的事情,而是一次有趣的C++世界之旅。

            如果你是一位已經(jīng)對(duì)C++有所了解的C++中高級(jí)用戶,正在尋求在C++方面更上層樓,這本書(shū)也同樣適合你。本書(shū)中形象生動(dòng)的比喻,可以讓你對(duì)整個(gè)C++世界有一個(gè)更加通透的認(rèn)識(shí)和理解;豐富的實(shí)踐經(jīng)驗(yàn),讓你從一個(gè)只是掌握語(yǔ)法知識(shí)的新手成長(zhǎng)為
            一個(gè) 經(jīng)驗(yàn)豐富的高手;本書(shū)還介紹了最新標(biāo)準(zhǔn)C++0x中最重要的特性,包括PPL并行模式庫(kù)、右值引用、智能指針等等,讓你時(shí)刻走在C++技術(shù)發(fā)展的潮頭。

            《我的第一本C++書(shū)》,每一個(gè)C++學(xué)習(xí)者都值得擁有

            更多詳細(xì)信息,歡迎訪問(wèn)

            http://imcc.blogbus.com

            posted @ 2011-05-28 10:43 陳良喬——《我的第一本C++書(shū)》 閱讀(1459) | 評(píng)論 (1)編輯 收藏

            2012年5月10日 #

            如何使用C++11中的條件變量

            原文來(lái)自:http://chenlq.net/vc11-bit-sweet-condition-variable-condition_variable-header-files.html 天啊,cppblog的編輯器能不能再爛一點(diǎn)? 有興趣的同學(xué),去看原文吧,無(wú)語(yǔ)了 :( 條件變量,是C++11中為了簡(jiǎn)化線程之間訪問(wèn)某個(gè)共享資源而提出的。在這個(gè)應(yīng)用場(chǎng)景中,這個(gè)共享資源往往表現(xiàn)為某種條件。例如在生產(chǎn)者-消費(fèi)者模式中,我們往往需要判斷用于存放產(chǎn)品的容器是在什么狀態(tài)(條件)下。如果容器是空的,生產(chǎn)者線程可以繼續(xù),而消費(fèi)者線程則需要暫停,而如果容器已經(jīng)滿了,生產(chǎn)者線程需要暫停,而消費(fèi)者線程可以繼續(xù)。而在這個(gè)場(chǎng)景中,我們就可以用條件變量來(lái)協(xié)調(diào)兩個(gè)線程之間的動(dòng)作。關(guān)于條件變量在生產(chǎn)者-消費(fèi)者模式下的應(yīng)用,我給出了一個(gè)例子。 條件變量在協(xié)調(diào)兩個(gè)線程之間的協(xié)作的時(shí)候非常有用,我們這里再補(bǔ)充一個(gè)例子。假設(shè)我們需要為政府設(shè)計(jì)一個(gè)程序來(lái)管理路燈。在這里,我們用一個(gè)線程來(lái)檢查是否到了觀燈的時(shí)間,而另外一個(gè)線程則負(fù)責(zé)在條件滿足后關(guān)閉路燈。 #include #include // 時(shí)間工具 #include // 線程 #include // 條件變量 #include // 互斥 using namespace std; using namespace std::chrono; // 條件變量 condition_variable cond; // 互斥 mutex m; // 表示條件的共享資源 bool morning = false; // 檢查是否到了關(guān)燈的時(shí)間 void check() { // 記錄開(kāi)始時(shí)間 auto start = system_clock::now(); do { // 當(dāng)前線程休眠1000毫秒 this_thread::sleep_for(milliseconds(1000)); cout<<"it is still night."<<endl; } // 檢查是否已經(jīng)到了關(guān)燈的時(shí)刻 // 這里用seconds(4)表示路燈持續(xù)4秒 while ( system_clock::now() < start + seconds(4)); // 到達(dá)關(guān)燈時(shí)間,鎖定互斥對(duì)象, // 修改表示條件的共享數(shù)據(jù)morning lock_guard lk(m); cout<<"it is morning."<<endl; morning = true; // 用notify_one()通知另外的線程,條件已經(jīng)發(fā)送變化 cond.notify_one(); } /// 關(guān)燈線程 void turnoff() { // 鎖定互斥對(duì)象,訪問(wèn)表示條件的共享資源morning unique_lock lk(m); // 構(gòu)造一個(gè)循環(huán),只要條件沒(méi)有滿足 // 就一直執(zhí)行條件變量的wait()方法,讓當(dāng)前線程等待 while(!morning) { cond.wait(lk); } // 條件滿足。執(zhí)行關(guān)燈動(dòng)作 cout<<"turn off the light."<<endl; } int main(int argc, char* argv[]) { // 創(chuàng)建兩個(gè)線程,分別執(zhí)行檢查和關(guān)燈的動(dòng)作 thread c(check); thread t(turnoff); c.join(); t.join(); return 0; } 從這個(gè)例子中,我們可以得到這樣一些使用條件變量的要點(diǎn): 條件變量總是需要與一個(gè)表示條件的共享資源以及對(duì)這個(gè)共享資源進(jìn)行訪問(wèn)控制的互斥對(duì)象。這就是我們?cè)诔绦虻拈_(kāi)始部分定義的morning,m和cond。 // 條件變量 condition_variable cond; // 互斥 mutex m; // 表示條件的共享資源 bool morning = false; 這三者幾乎總是相伴同時(shí)出現(xiàn)。 在一個(gè)線程中,我們需要在條件滿足的時(shí)候修改表示條件的共享資源的值,然后用條件變量的notify_one()或者notify_all()通知正在等待的線程。這就是 // 到達(dá)關(guān)燈時(shí)間,鎖定互斥對(duì)象, // 修改表示條件的共享數(shù)據(jù)morning lock_guard lk(m); cout<<"it is morning."<<endl; morning = true; // 用notify_one()通知另外的線程,條件已經(jīng)發(fā)送變化 cond.notify_one(); 而在另外一個(gè)線程中,我們需要構(gòu)造一個(gè)以共享資源為條件的無(wú)限循環(huán),當(dāng)條件無(wú)法滿足時(shí),就用條件變量的wait()或者wait_until()等函數(shù)進(jìn)行等待,直到條件得到滿足,循環(huán)結(jié)束。 // 鎖定互斥對(duì)象,訪問(wèn)表示條件的共享資源morning unique_lock lk(m); // 構(gòu)造一個(gè)循環(huán),只要條件沒(méi)有滿足 // 就一直執(zhí)行條件變量的wait()方法,讓當(dāng)前線程等待 while(!morning) { cond.wait(lk); } 總結(jié)起來(lái),條件變量簡(jiǎn)化了對(duì)表示條件的共享資源的訪問(wèn),也省去了對(duì)共享資源的頻繁的鎖操作,進(jìn)一步提高了效率。

            posted @ 2012-05-10 17:59 陳良喬——《我的第一本C++書(shū)》 閱讀(2171) | 評(píng)論 (0)編輯 收藏

            2012年5月1日 #

            用C++11 FAQ中文版學(xué)習(xí)C++11,輕松而簡(jiǎn)單!

            學(xué)習(xí)C++11正當(dāng)時(shí),C++11 FAQ中文版本幫你快速了解和學(xué)習(xí)C++11,從而快人一步,登上C++11這趟快速列車 >> http://chenlq.net/cpp11-faq-chs對(duì)此你有什么意見(jiàn)和建議呢? C++11標(biāo)準(zhǔn)已經(jīng)在2011年正式通過(guò)。而各大編譯器也即將實(shí)現(xiàn)對(duì)C++11的完全支持。C++11可以說(shuō)是C++歷史上最大的一次變革,增加了大量的語(yǔ)法特性,標(biāo)準(zhǔn)庫(kù)也得到了極大的增強(qiáng)。C++11 FAQ中文版是我們學(xué)習(xí)和掌握這一新標(biāo)準(zhǔn)的快捷通道。 http://chenlq.net/cpp11-faq-chs

            posted @ 2012-05-01 11:01 陳良喬——《我的第一本C++書(shū)》 閱讀(2362) | 評(píng)論 (0)編輯 收藏

            2011年11月12日 #

            C++小品:她來(lái)聽(tīng)我的演唱會(huì)——C++11中的隨機(jī)數(shù)、線程(thread)、互斥(mutex)和條件變量(condition)

            源文來(lái)自: http://imcc.blogbus.com/logs/172675220.html
            ?

            在新頒布的C++新標(biāo)準(zhǔn)C++11中,最令人激動(dòng)人心的,我想不是auto關(guān)鍵字,也不是Lambda表達(dá)式,而是其中的對(duì)并行計(jì)算的支持——新的線程庫(kù)(thread)的加入。

            多核心CPU的普及應(yīng)用,C++的主要應(yīng)用領(lǐng)域,服務(wù)器程序,高性能計(jì)算等等,都對(duì)并行計(jì)算提出了新的要求,而這次C++中全新添加的線程庫(kù),就是 對(duì)這一趨勢(shì)的應(yīng)對(duì)。現(xiàn)在,C++程序員可以輕松地編寫(xiě)多線程的程序,而無(wú)需借助系統(tǒng)API或者是第三方程序庫(kù)的支持。線程庫(kù)的加入給C++帶來(lái)的變化,無(wú) 異于 194,翻身的程序員們把歌唱。

            C++11中的線程庫(kù),很大程度上直接來(lái)自boost這塊C++的試驗(yàn)田,其基本架構(gòu)和組件都完全相同,如果你是一個(gè)boost線程庫(kù)的使用者,那 么在C++11中,你會(huì)感覺(jué)到是回到了老家一樣,到處都是熟人。而如果你是一個(gè)完全的新手,也不要緊,C++11中的線程庫(kù)非常簡(jiǎn)單,任何人都可以輕松上 手,我就是這樣,但是要深究,還得好好學(xué)習(xí)。

            下面是一個(gè)簡(jiǎn)單的例子,用到了線程庫(kù)中的線程(thread),互斥(mutex),條件變量(condition),來(lái)模擬一個(gè)演唱會(huì)的入場(chǎng)檢票的場(chǎng)景,另外,為了模擬觀眾,用到了C++11中的新的隨機(jī)數(shù)的產(chǎn)生,模擬一個(gè)正態(tài)分布的訪客人群。不說(shuō)了,還是看代碼:

            #include <iostream>
            #include <queue>
            #include <vector>
            // 隨機(jī)數(shù)
            #include <random>
            // 這里,我使用了boost實(shí)現(xiàn)的線程庫(kù),如果你的編譯器已經(jīng)支持C++11,則使用<thread>是一樣的
            #include <boost\thread.hpp>
            #include <boost\thread\locks.hpp>
            #include <boost\thread\condition.hpp>

            using namespace std;
            using namespace boost;

            // 共享資源和互斥對(duì)象
            mutex mtx;
            bool finish = false;? // 表示觀眾到來(lái)是否結(jié)束

            // 觀眾,主要是為了表示檢票過(guò)程中的檢票耗費(fèi)時(shí)間
            class viewer
            {
            public:
            ??? void check()
            ??? {
            ??? ??? // 線程等待
            ??????? posix_time::milliseconds worktime(400);?
            ??? ??? this_thread::sleep(worktime);???
            ??? }
            ??? void arrival(int t)
            ??? {
            ??? ??? posix_time::seconds arrtime(t);?
            ??? ??? this_thread::sleep(arrtime);???
            ??? }
            };
            // 檢票口
            // 它有一個(gè)隊(duì)列,用于保存到來(lái)的觀眾,并且用一個(gè)線程來(lái)處理隊(duì)列中的觀眾
            class gate
            {
            ??? typedef boost::mutex::scoped_lock scoped_lock;
            public:
            ??? gate():count(0),no(0){};
            ??? // 啟動(dòng)線程
            ??? void start(int n)
            ??? {
            ??? ??? no = n;
            ??? ??? t = thread(&gate::check,this);
            ??? }

            ??? // 檢票
            ??? void check()
            ??? {
            ??? ??? // 無(wú)限循環(huán),知道觀眾數(shù)為0且不會(huì)有新的觀眾到來(lái)
            ??? ??? while(true)
            ??? ??? {
            ??? ??? ??? viewer v;
            ??? ??? ??? {
            ??? ??? ??? ??? // 鎖定互斥對(duì)象,開(kāi)始訪問(wèn)對(duì)列
            ??? ??? ??? ??? scoped_lock lock(m);
            ??? ??? ??? ??? if(0==vque.size())? // 如果隊(duì)列為空
            ??? ??? ??? ??? {
            ??? ??? ??? ??? ??? {
            ??? ??? ??? ??? ??? // 判斷是否還會(huì)有新的觀眾到來(lái),也即是表示到達(dá)的線程是否結(jié)束
            ??????????????????? scoped_lock finlk(mtx);
            ??? ??? ??? ??? ??? if(finish)
            ??? ??? ??? ??? ??? ??? return; // 如果已經(jīng)結(jié)束,檢票也同樣結(jié)束
            ??? ??? ??? ??? ??? }
            ??? ??? ??? ??? ??? // 如果觀眾數(shù)為0,則等待新的觀眾的到來(lái)
            ??????????????????? while(0 == vque.size())
            ??? ??? ??? ??? ??? {???
            ??? ??? ??? ??? ??? ????? // 這里的wait()是條件變量的關(guān)鍵,它會(huì)先是否lock所鎖定的互斥對(duì)象m一定時(shí)間,
            ????????????????????????? // 然后再次鎖定,接著進(jìn)行(0==vque.size())的判斷。如此往復(fù),知道size不等于0,
            ????????????????????????? // 循環(huán)條件無(wú)法滿足而結(jié)束循環(huán),這里表達(dá)的條件就是,只有size!=0,也就是隊(duì)列中有
            ????????????????????????? // 觀眾才繼續(xù)向下。
            ????????????????????????? cond.wait(lock);
            ??? ??? ??? ??? ??? }
            ??? ??? ??? ??? }
            ??? ??? ??? ??? // 從對(duì)列中獲得觀眾,對(duì)其進(jìn)行檢票
            ??? ??? ??? ??? v = vque.front();
            ??? ??? ??? ??? vque.pop();
            ??? ??? ??? ??? cond.notify_one(); // 這里是通知添加觀眾的進(jìn)程,表示隊(duì)列已經(jīng)有空位置了,可以添加新的觀眾
            ??? ??? ??? }
            ??? ??? ??? v.check();
            ??? ??? ??? ++count;
            ??? ??? }
            ??? }
            ??? // 將觀眾添加到隊(duì)列
            ??? void add(viewer v)
            ??? {

            ??? ??? // 同樣運(yùn)用條件變量,判斷隊(duì)列是否已經(jīng)滿了
            ??????? // 只有在隊(duì)列尚未滿的情況下才向下繼續(xù)
            ??????? scoped_lock lock(m);
            ??? ??? while(vque.size() >= 15 )
            ??? ??? {
            ??? ??? ??? cond.wait(lock);
            ??? ??? }
            ??? ??? vque.push(v); // 將觀眾添加到隊(duì)列
            ??? ??? cond.notify_one();? // 通知檢票進(jìn)程,新的觀眾進(jìn)入隊(duì)列,這樣在size=0時(shí)等待的條件可以更新
            ??? }
            ??? int getcount()
            ??? {
            ??? ??? return count;
            ??? }
            ??? int getno()
            ??? {
            ??? ??? return no;
            ??? }
            ??? // 等待線程執(zhí)行完畢返回
            ??? void join()
            ??? {
            ??? ??? t.join();
            ??? }
            private:
            ??? thread t;
            ??? mutex m;
            ??? condition cond;
            ??? queue<viewer> vque;
            ??? int count;
            ??? int no;
            };

            // 一共有10個(gè)檢票口
            vector<gate> vgates(10);

            // 用隨機(jī)數(shù)模擬觀眾到達(dá)
            void arrival()
            {???
            ??? default_random_engine re{}; // 產(chǎn)生一個(gè)均值為31的正態(tài)分布的隨機(jī)數(shù)
            ??? normal_distribution<double> nd(31,8);

            ??? // 將隨機(jī)數(shù)引擎和分布綁定一個(gè)函數(shù)對(duì)象
            ??? auto norm = std::bind(nd, re);
            ??? // 保存隨機(jī)數(shù)的容器
            ??? vector<int> mn(64);
            ???
            ??? // 產(chǎn)生隨機(jī)數(shù)
            ??? for(int i = 0;i<700;++i)
            ??? ??? ++mn[round(norm())];
            ???
            ??? int secs = 100;
            ??? // 產(chǎn)生0到9的隨機(jī)數(shù),表示觀眾隨機(jī)地到達(dá)某一個(gè)檢票口
            ??? uniform_int_distribution<int>? index{0,9};
            ??? ?
            ??? // 進(jìn)入檢票口隊(duì)列
            ??? for(auto i:mn)
            ??? {
            ??? ??? cout<<i<<endl;
            ??? ??? for(auto vi = 1; vi <= i; ++vi)
            ??? ??? {
            ??? ??? ??? // 將觀眾添加到某個(gè)gate的隊(duì)列中
            ???????????? (vgates[index(re)]).add(viewer());
            ??? ??? ??? // 等待一段時(shí)間
            ??? ??? ??? int t = round(secs/(float)(i+1));
            ??? ??? ??? this_thread::sleep(
            ??? ??? ??? posix_time::milliseconds(t));
            ??? ??? }
            ??? }
            ??? // 觀眾已經(jīng)全部到達(dá),進(jìn)入隊(duì)列
            ???? cout<<"finish"<<endl;
            ??? mtx.lock();
            ??? finish = true;
            ??? mtx.unlock();
            ??? //cout<<"unlock"<<endl;
            }

            int main()
            {
            ??? int i = 1;
            ??? // 啟動(dòng)檢票線程
            ??? for(gate& g:vgates)
            ??? {
            ??? ??? g.start(i);
            ??? ??? ++i;
            ??? }
            ??? // 啟動(dòng)到達(dá)線程,看看,在C++11中新線程的創(chuàng)建就這么簡(jiǎn)單
            ??? thread arr = thread(arrival);
            ??? // 等待線程結(jié)束
            ??? arr.join();
            ??? int total = 0;
            ??? // 等待檢票線程結(jié)束,并輸出處理的人數(shù)
            ??? for(gate& g:vgates)
            ??? {
            ??? ??? g.join();
            ??? ??? total += g.getcount();
            ??? ??? cout<<"gate "<<g.getno()
            ??? ??? ??? <<" processed "<<g.getcount()<<" viewers."<<endl;
            ??? }
            ??? cout<<"there are "<<total<<"viewers in total."<<endl;
            ??? return 0;
            }
            這就是一個(gè)線程庫(kù)的簡(jiǎn)單應(yīng)用,模擬了非常復(fù)雜的場(chǎng)景。

            因?yàn)樽约簩?duì)多線程開(kāi)發(fā)還不太熟悉,這個(gè)程序在某些特定條件下會(huì)產(chǎn)生了死鎖,還有待進(jìn)一步完善

            posted @ 2011-11-12 10:29 陳良喬——《我的第一本C++書(shū)》 閱讀(3450) | 評(píng)論 (3)編輯 收藏

            2011年9月20日 #

            C++小品:weak_ptr與傳達(dá)室的花名冊(cè)

            原文來(lái)自

            http://imcc.blogbus.com/logs/162618478.html

            在C++11中,我們可以使用shared_ptr管理某個(gè)對(duì)象的所有權(quán),負(fù)責(zé)對(duì)象的析構(gòu)。然而在某些情況下,我們只是希望安全的訪問(wèn)某個(gè)對(duì)象,而不想擁有這個(gè)對(duì)象的所有權(quán),對(duì)這個(gè)的析構(gòu)負(fù)責(zé)(有點(diǎn)像電視劇中的那些不負(fù)責(zé)任的男人哦,只是玩玩而已,不會(huì)負(fù)責(zé))。在這種情況下,我們可以使用表示弱引用的weak_ptr。

            weak_ptr可以由一個(gè)shared_ptr構(gòu)建,表示這個(gè)weak_ptr擁有這個(gè)shared_ptr所指向的對(duì)象的訪問(wèn)權(quán),注意,這里僅僅是訪問(wèn)權(quán),它不會(huì)改變智能指針的引用計(jì)數(shù),自然也就不會(huì)去析構(gòu)這個(gè)對(duì)象。利用weak_ptr,我們就可以安全地訪問(wèn)那些不具備所有權(quán)的對(duì)象。

            一個(gè)現(xiàn)實(shí)中的例子就是學(xué)校的傳達(dá)室,傳達(dá)室擁有一本學(xué)生的名單,如果某個(gè)電話來(lái)了找某個(gè)學(xué)生,傳達(dá)室會(huì)根據(jù)花名冊(cè)去嘗試訪問(wèn)這個(gè)學(xué)生,如果這個(gè)學(xué)生還在學(xué)校,就直接呼叫這個(gè)學(xué)生,如果已經(jīng)離開(kāi)了,這給這個(gè)學(xué)生留一個(gè)消息。在這里,花名冊(cè)上的學(xué)生可能還在學(xué)校(對(duì)象還存在),也可能已經(jīng)離開(kāi)學(xué)校(對(duì)象已經(jīng)析構(gòu)),我們都需要對(duì)其進(jìn)行訪問(wèn),而weak_ptr就是用來(lái)訪問(wèn)這種不確定是否存在的對(duì)象的。

            #include <iostream>
            #include <map>
            #include <algorithm>
            #include <memory>
            using namespace std;

            // 學(xué)校的同學(xué)
            class human
            {
            public:
            human(string _n):name(_n)
            {};
            ~human()
            {
            cout<<name<<" was destructed."<<endl;
            }
            void call() // 嘿,有個(gè)電話找你
            {
            cout<<name<<" was called."<<endl;
            }
            private:
            string name;
            };
            // 傳達(dá)室
            class doorman
            {
            public:
            doorman(map<string,shared_ptr<human>> humans)
            {
            // 根據(jù)學(xué)生對(duì)象構(gòu)造花名冊(cè),注意其中保存的是有shared_ptr構(gòu)造的weak_ptr
            for_each(humans.begin(),humans.end(),
            [&names](pair<string,shared_ptr<human>> h)
            {
            names[h.first] = weak_ptr<human>(h.second);
            });
            }
            // 有個(gè)電話打到了傳達(dá)室
            void call(string name)
            {
            // 找找看,花名冊(cè)中有沒(méi)有這個(gè)學(xué)生
            auto it = names.find(name);
            // 如果有
            if(it!=names.end())
            {
            auto man = (*it).second;
            // 用lock()函數(shù)嘗試獲得weak_ptr所指向的shared_ptr,保存為p
            if(auto p = man.lock())
            p->call(); // 如果找到關(guān)聯(lián)的shared_ptr,也就是這個(gè)對(duì)象還存在,也就是這個(gè)學(xué)生還在學(xué)校,呼叫之
            else // 如果無(wú)法得到關(guān)聯(lián)的shared_ptr,表示這個(gè)對(duì)象已經(jīng)不存在了,學(xué)生離開(kāi)了學(xué)校,只能給他留一個(gè)消息了
            {
            leavemsg(name);
            }
            }
            else // 如果花名冊(cè)中根本沒(méi)有這個(gè)名字
            {
            cout<<name<<" is not in the school."<<endl;
            }
            }
            void leavemsg(string name)
            {
            cout<<name<<" has left school.I will leave a message for him."<<endl;
            }
            private:
            map<string,weak_ptr<human>> names; // 傳達(dá)室的花名冊(cè)
            };
            int main()
            {
            // 學(xué)校的學(xué)生
            map<string,shared_ptr<human>> humans;
            humans["Jiawei"] = make_shared<human>("Jiawei");
            humans["Chen"] = make_shared<human>("Chen");
            humans["Xibei"] = make_shared<human>("Xibei");

            // 傳達(dá)室,根據(jù)學(xué)生構(gòu)造一個(gè)花名冊(cè)
            doorman dm(humans);
            // 有人找Chen
            dm.call("Chen");
            // 有人找Fu
            dm.call("Fu");

            // Chen離開(kāi)學(xué)校,對(duì)象被析構(gòu)
            humans.erase("Chen");
            // 又有人打來(lái)電話找Chen,這時(shí)他已經(jīng)不在學(xué)校,只能給他留一個(gè)消息了
            dm.call("Chen");
            // 有人找Jiawei,她還在學(xué)校呢,直接叫她
            dm.call("Jiawei");

            return 0;
            }
            從這段程序的輸出,我們也可以看出,我們?cè)趧h除humans容器中的Chen這個(gè)元素是,對(duì)應(yīng)的human對(duì)象也被析構(gòu),doorman中指向這個(gè)對(duì)象的weak_ptr并不影響它的析構(gòu),當(dāng)我們?cè)俅螄L試訪問(wèn)這個(gè)對(duì)象時(shí)候,lock()無(wú)法成功獲得與之關(guān)聯(lián)的shared_ptr,也就無(wú)法對(duì)其進(jìn)行訪問(wèn)了。

            Chen was called.
            Fu is not in the school.
            Chen was destructed.
            Chen has left school.I will leave a message for him.
            Jiawei was called.
            Xibei was destructed.
            Jiawei was destructed.

            這里大家可能會(huì)問(wèn),為什么不在doorman中使用裸指針呢?。。。

            那么,為什么不直接使用shared_ptr呢? 參考原文。

            總結(jié)起來(lái),weak_ptr用于訪問(wèn)了那些不具備所有權(quán)的,可能存在也可能不存在的對(duì)象。

            posted @ 2011-09-20 16:29 陳良喬——《我的第一本C++書(shū)》 閱讀(1803) | 評(píng)論 (0)編輯 收藏

            2011年9月10日 #

            C++小品:吃火鍋與shared_ptr,指針,拷貝構(gòu)造函數(shù)和delete

            原文來(lái)自

            http://imcc.blogbus.com/

            C++小品:吃火鍋與shared_ptr,指針,拷貝構(gòu)造函數(shù)和delete

            讀者Terry問(wèn)到一個(gè)關(guān)于拷貝構(gòu)造函數(shù)的問(wèn)題,大家可以參考答Terry:拷貝構(gòu)造函數(shù),其中論述了拷貝構(gòu)造函數(shù)的必要性,然而,任何事物都是具有兩面性的,有時(shí)候我們需要自己定義類的拷貝構(gòu)造函數(shù)來(lái)完成類的拷貝,然后,有的時(shí)候,這種以拷貝一個(gè)對(duì)象來(lái)完成另外一個(gè)對(duì)象的創(chuàng)建是不合理的(也就是在現(xiàn)實(shí)世界中,這種對(duì)象沒(méi)有可復(fù)制性,例如,人民幣),是應(yīng)該被禁止的。我們來(lái)舉一個(gè)吃火鍋的例子:

            // 火鍋,可以從中取出其中燙的東西
            class hotpot
            {
            public:
            hotpot(string f) : food(f)
            {
            }
            string fetch()
            {
            return food;
            }
            private:
            string food;
            };

            // 吃火鍋用的碗,當(dāng)然是每個(gè)人專用的
            class bowl
            {
            public:
            bowl(string o) : owner(o)
            {
            }
            void put(string food)
            {
            cout<<"put "< }

            private:
            string owner;
            };
            // 吃火鍋的人
            class human
            {
            public:
            // 名子和吃的火鍋
            human(string n,shared_ptr ppot) : name(n),pot(ppot)
            {
            pbowl = new bowl(name);
            };
            // OK了,從火鍋中取出來(lái)放到自己的碗里
            void fetch()
            {
            string food = pot->fetch();
            // 放到自己的碗里
            coutput(food);
            }

            private:
            string name;
            shared_ptr pot;
            bowl* pbowl;
            };
            int main()
            {
            // 服務(wù)員端上來(lái)牛肉火鍋
            shared_ptr fpot(new hotpot("beaf"));
            // terry入席
            human terry("terry",fpot);
            // 又來(lái)了一個(gè)姓陳的,這里用的是默認(rèn)的拷貝構(gòu)造函數(shù)來(lái)創(chuàng)建terry的副本
            human chen = terry;
            // terry夾了一塊肉
            terry.fetch();
            // 陳先生也夾了一塊肉
            chen.fetch();

            return 0;
            }

            到這里,似乎看起來(lái)一切OK,然而從程序輸出中我們卻發(fā)現(xiàn)了問(wèn)題:

            terry put beaf into terry's bowl.
            terry put beaf into terry's bowl.

            O my god!明明是兩個(gè)人(terry和chen),但是好像卻只有一個(gè)人做了兩次,陳先生也把肉加到了terry的碗里。

            這就是當(dāng)類中有指針類型的數(shù)據(jù)成員時(shí),使用默認(rèn)的拷貝構(gòu)造函數(shù)所帶來(lái)的問(wèn)題,導(dǎo)致其中的某些指針成員沒(méi)有被合理地初始化,這別是當(dāng)這些指針指向的是與這個(gè)對(duì)象(human)有所屬關(guān)系的資源(bowl),在這種時(shí)候,我們必須自己定義類的拷貝構(gòu)造函數(shù),完成指針成員的合理初始化。在human中添加一個(gè)拷貝構(gòu)造函數(shù)

            human(const human& h)
            {
            // 兩個(gè)人顯然不能同名,所以只好給個(gè)無(wú)名氏了
            name = "unknown";
            // 使用不同的碗
            // bowl和human有所屬關(guān)系,所以這里必須創(chuàng)建新的對(duì)象
            pbowl = new bowl(name);
            // 不過(guò)可以吃同一個(gè)火鍋
            // pot和human并沒(méi)有所屬關(guān)系,所以可以共享一個(gè)對(duì)象
            pot = h.pot;
            };

            添加拷貝構(gòu)造構(gòu)造函數(shù)之后,兩個(gè)人不會(huì)將東西放到同一個(gè)碗中了,自己取得東西不會(huì)放到別人的碗里:

            terry put beaf into terry's bowl.
            unknown put beaf into unknown's bowl.

            這樣修改好多了,至少兩個(gè)人不會(huì)用同一個(gè)碗了。然而,這樣還是有問(wèn)題,我們無(wú)法給第二個(gè)人命名,他成了無(wú)名氏了,這就是類當(dāng)中的那些沒(méi)有可復(fù)制性的數(shù)據(jù)成員(一個(gè)人的名字自然不可以復(fù)制給另外一個(gè)人,如果human中有個(gè)wife,那肯定要上演世界大戰(zhàn)了),拷貝構(gòu)造函數(shù)就會(huì)產(chǎn)生這樣的問(wèn)題。

            實(shí)際上,對(duì)于這類不具備可復(fù)制性的對(duì)象,為了不引起混亂,其拷貝構(gòu)造操作是應(yīng)當(dāng)被禁止的,新標(biāo)準(zhǔn)C++11就注意到了這個(gè)問(wèn)題,提供了一個(gè)delete關(guān)鍵字來(lái)禁用某些可能存在的(即使你規(guī)定human不可復(fù)制,也無(wú)法阻止程序員在使用human時(shí)寫(xiě)出human chen = terry這樣的不合理的代碼)默認(rèn)的(類的拷貝構(gòu)造函數(shù)是默認(rèn)提供的,對(duì)于那些不具備可復(fù)制性的類來(lái)說(shuō),這簡(jiǎn)直是畫(huà)蛇添足,好心辦了壞事情)不合理的操作,這樣,我們就不能使用拷貝 構(gòu)造函數(shù)了:

            // 禁用human的拷貝構(gòu)造函數(shù)
            human(const human& h) = delete;

            經(jīng)過(guò)這樣的定義,當(dāng)我們?cè)诖a中嘗試將一個(gè)對(duì)象復(fù)制給另外一個(gè)對(duì)象(會(huì)調(diào)用拷貝構(gòu)造函數(shù))時(shí),編譯器就會(huì)出錯(cuò)誤提示,提醒程序員:hi,這樣可不行,我是獨(dú)一無(wú)二的,不能夠被復(fù)制

            human chen = terry;

            編譯器給這樣的提示:
            Noname1.cpp:41:2: error: deleted function 'human::human(const human&)'
            Noname1.cpp:59:15: error: used here

            所以,總結(jié)起來(lái),在使用拷貝構(gòu)造函數(shù)時(shí),有兩個(gè)需要注意的地方:

            • 如果類當(dāng)中有指向具有所屬關(guān)系的對(duì)象的指針時(shí)(human中的pbowl指向的是屬于human的bowl對(duì)象,每個(gè)human對(duì)象應(yīng)該有專屬的bowl對(duì)象),我們必須自定義拷貝構(gòu)造函數(shù),為這個(gè)指針創(chuàng)建屬于自己的專屬對(duì)象。
            • 如果這個(gè)類當(dāng)中,有不具備可復(fù)制性的成員(例如name,rmb,wife等),為了防止對(duì)象被錯(cuò)誤的復(fù)制(即使我們沒(méi)有定義拷貝構(gòu)造函數(shù),編譯器也會(huì)默認(rèn)提供,真是多此一舉),我們必須用delete禁用拷貝構(gòu)造函數(shù),這樣才能保證對(duì)象不會(huì)被錯(cuò)誤地復(fù)制。關(guān)于human的克隆技術(shù),應(yīng)當(dāng)是被明令禁止(delete)的。

            posted @ 2011-09-10 16:10 陳良喬——《我的第一本C++書(shū)》 閱讀(2210) | 評(píng)論 (0)編輯 收藏

            2011年7月23日 #

            函數(shù)調(diào)用機(jī)制

            更多來(lái)自:http://imcc.blogbus.com

            5.1.2 函數(shù)調(diào)用機(jī)制

            在學(xué)習(xí)編寫(xiě)函數(shù)之前,我們首先要了解函數(shù)的調(diào)用機(jī)制,學(xué)會(huì)如何調(diào)用一個(gè)已經(jīng)存在的函數(shù)。世界上已經(jīng)有很多函數(shù),我們可以直接調(diào)用這些函數(shù)來(lái)完成日常任務(wù)。世界上已經(jīng)有很多輪子,我們沒(méi)有必要再去發(fā)明更多同樣的輪子,只需要用好它們就可以了。在實(shí)際的開(kāi)發(fā)中,可供調(diào)用的現(xiàn)有函數(shù)主要有編譯器提供的庫(kù)函數(shù)、Windows API及第三方提供的函數(shù)庫(kù)等。通過(guò)調(diào)用他人的函數(shù),可以復(fù)用他人的開(kāi)發(fā)成果,在其開(kāi)發(fā)成果的基礎(chǔ)上,實(shí)現(xiàn)快速開(kāi)發(fā),如圖5-3所示。

            有了別人提供的函數(shù),就可以調(diào)用這些函數(shù)來(lái)完成自己的功能。兩個(gè)函數(shù)之間的關(guān)系是調(diào)用與被調(diào)用的關(guān)系,我們把調(diào)用其他函數(shù)的函數(shù)稱為主調(diào)函數(shù),被其他函數(shù)調(diào)用的函數(shù)稱為被調(diào)函數(shù)。一個(gè)函數(shù)是主調(diào)函數(shù)還是被調(diào)函數(shù)并不是絕對(duì)的,要根據(jù)其所處的相對(duì)位置而定:如果一個(gè)函數(shù)內(nèi)部有函數(shù),則相對(duì)其內(nèi)部的函數(shù)它就是主調(diào)函數(shù);如果它的外部有函數(shù),則相對(duì)其外部函數(shù)它就是被調(diào)函數(shù)。

            clip_image002

            圖5-3 天上掉下個(gè)函數(shù)庫(kù)

            posted @ 2011-07-23 11:27 陳良喬——《我的第一本C++書(shū)》 閱讀(1877) | 評(píng)論 (1)編輯 收藏

            2011年7月22日 #

            將程序裝到箱子中:函數(shù)的聲明和定義

            更多來(lái)自:http://imcc.blogbus.com

            5.1.1 將程序裝到箱子中:函數(shù)的聲明和定義

            提問(wèn):把大象裝到冰箱中需要幾步?

            回答:需要三步。第一,打開(kāi)冰箱;第二,把大象放進(jìn)冰箱;第三,關(guān)上冰箱。

            提問(wèn):那么,把一個(gè)程序放進(jìn)箱子需要幾步?

            回答:需要兩步。第一,聲明一個(gè)函數(shù);第二,定義這個(gè)函數(shù)。

            沒(méi)錯(cuò),把一個(gè)函數(shù)放進(jìn)箱子比把大象放進(jìn)冰箱還要簡(jiǎn)單。當(dāng)分析一段長(zhǎng)的程序代碼時(shí),往往會(huì)發(fā)現(xiàn)一些代碼所實(shí)現(xiàn)的功能相對(duì)比較獨(dú)立。我們將程序中這些相對(duì)比較獨(dú)立的功能代碼組織到一起,用函數(shù)對(duì)其進(jìn)行封裝,也就是將一個(gè)較長(zhǎng)的程序分放到各個(gè)函數(shù)箱子中。

            要裝東西,先得準(zhǔn)備好箱子。為了找到具體功能實(shí)現(xiàn)代碼的箱子,需要給箱子貼上標(biāo)簽,這個(gè)標(biāo)簽就是函數(shù)的聲明,如圖5-2所示。

            clip_image002

            圖5-2 聲明一個(gè)函數(shù),為箱子貼上

            posted @ 2011-07-22 13:25 陳良喬——《我的第一本C++書(shū)》 閱讀(1456) | 評(píng)論 (0)編輯 收藏

            2011年7月21日 #

            把程序裝進(jìn)箱子:用函數(shù)封裝程序功能

            更多來(lái)自:http://imcc.blogbus.com

            ? 把程序裝進(jìn)箱子:用函數(shù)封裝程序功能clip_image001

            在完成豪華的工資統(tǒng)計(jì)程序之后,我們信心倍增,開(kāi)始向C++世界的更深遠(yuǎn)處探索。

            現(xiàn)在,可以使用各種數(shù)據(jù)類型和程序流程控制結(jié)構(gòu)來(lái)編寫(xiě)完整的程序了。但是,隨著要處理的問(wèn)題越來(lái)越復(fù)雜,程序的代碼也越來(lái)越復(fù)雜,主函數(shù)也越來(lái)越長(zhǎng)了。這就像我們將所有東西都堆放到一個(gè)倉(cāng)庫(kù)中,隨著東西越來(lái)越多,倉(cāng)庫(kù)慢慢就被各種東西堆滿了,顯得雜亂無(wú)章,管理起來(lái)非常困難。面對(duì)一個(gè)雜亂無(wú)章的倉(cāng)庫(kù),聰明的倉(cāng)庫(kù)管理員提供了一個(gè)很好的管理辦法:將東西分門別類地裝進(jìn)箱子,然后有序地堆放各個(gè)箱子。

            這個(gè)好方法也可以用到程序設(shè)計(jì)中,把程序裝進(jìn)箱子,讓整個(gè)程序結(jié)構(gòu)清晰。

            clip_image003

            5.1 函數(shù)就是一個(gè)大箱子

            當(dāng)要處理的問(wèn)題越來(lái)越復(fù)雜,程序越來(lái)越龐大的時(shí)候,如果把這些程序代碼都放到主函數(shù)中,將使得整個(gè)主函數(shù)異常臃腫,這樣會(huì)給程序的維護(hù)帶來(lái)麻煩。同時(shí),要讓一個(gè)主函數(shù)來(lái)完成所有的事情,幾乎是一個(gè)不可能完成的任務(wù)。在這種情況下,可以根據(jù)“分而治之”的原則,按照功能的不同將大的程序進(jìn)行模塊劃分,具有相同功能的劃分到同一個(gè)模塊中,然后分別處理各個(gè)模塊。函數(shù),則成為模塊劃分的基本單位,是對(duì)一個(gè)小型問(wèn)題處理過(guò)程的一種抽象。這就像管理一個(gè)倉(cāng)庫(kù),總是將同類的東西放到同一個(gè)箱子中,然后通過(guò)管理這些箱子來(lái)管理整個(gè)倉(cāng)庫(kù)。在具體的開(kāi)發(fā)實(shí)踐中,我們先將相對(duì)獨(dú)立的、經(jīng)常使用的功能抽象為函數(shù),然后通過(guò)這些函數(shù)的組合來(lái)完成一個(gè)比較大的功能。舉一個(gè)簡(jiǎn)單的例子:看書(shū)看得肚子餓了,我們要泡方便面吃。這其實(shí)是一個(gè)很復(fù)雜的過(guò)程,因?yàn)檫@一過(guò)程中我們先要洗鍋,然后燒水,水燒開(kāi)后再泡面,吃完面后還要洗碗。如果把整個(gè)過(guò)程描述在主函數(shù)中,那么主函數(shù)會(huì)非常復(fù)雜,結(jié)構(gòu)混亂。這時(shí)就可以使用函數(shù)來(lái)封裝整個(gè)過(guò)程中的一些小步驟,讓整個(gè)主函數(shù)簡(jiǎn)化為對(duì)這些函數(shù)的調(diào)用,如圖5-1所示。

            clip_image005

            圖5-1 將程序封裝到箱子,分而治之

            posted @ 2011-07-21 09:45 陳良喬——《我的第一本C++書(shū)》 閱讀(1819) | 評(píng)論 (2)編輯 收藏

            2011年7月20日 #

            對(duì)循環(huán)進(jìn)行控制:break與continue

            更多來(lái)自:http://imcc.blogbus.com

            4.3.4 對(duì)循環(huán)進(jìn)行控制:break與continue

            // 大款的收支統(tǒng)計(jì)程序

            int nTotal = 0;

            int nInput = 0;

            do

            {

            cout<< "請(qǐng)輸入你的收入或支出:";

            cin>>nInput;

            if( 1000< nInput ) // 毛毛雨啊,就不用統(tǒng)計(jì)了

            continue;

            nTotal += nInput;

            }while( 0 != nInput );

            在這個(gè)大款的收支統(tǒng)計(jì)程序中,nInput接收用戶輸入后判斷其值是否小于1 000,如果小于1 000,則執(zhí)行continue關(guān)鍵字,跳過(guò)后面的加和語(yǔ)句“nTotal += nInput;”,而直接跳轉(zhuǎn)到對(duì)條件表達(dá)式“0 != nInput”的計(jì)算,判斷是否可以開(kāi)始下一次循環(huán)。值得注意的是,在for循環(huán)中,執(zhí)行continue后,控制條件變化的更改語(yǔ)句并沒(méi)有被跳過(guò),仍然將被執(zhí)行,然后再計(jì)算條件表達(dá)式,嘗試下一次循環(huán)。

            雖然break和continue都是在某種條件下跳出循環(huán),但是兩者有本質(zhì)的差別:break是跳出整個(gè)循環(huán),立刻結(jié)束循環(huán)語(yǔ)句的執(zhí)行;而continue只跳出本次循環(huán),繼續(xù)執(zhí)行下一次循環(huán)。圖4-6展示了break和continue之間的區(qū)別。

            clip_image002[4]

            圖4-6 break和continue之間的區(qū)別

            posted @ 2011-07-20 11:48 陳良喬——《我的第一本C++書(shū)》 閱讀(346) | 評(píng)論 (0)編輯 收藏

            2011年7月19日 #

            《我的第一本C++書(shū)》迷你書(shū)——看圖學(xué)C++免費(fèi)下載

            clip_image002

            The world is built on C++.

            —— Herb Sutter

            看得有趣、學(xué)得輕松

            看圖也能學(xué)C++?!

            沒(méi)錯(cuò),看圖也能學(xué)C++!

            這本迷你書(shū)是《我的第一本C++書(shū)》的迷你版,它抽取了《我的第一本C++書(shū)》中的全部的精美插圖,并配上相應(yīng)的解釋說(shuō)明。它以圖文并茂的生動(dòng)形式,向你講解那些所謂的高深的C++知識(shí),讓你對(duì)那些抽象的C++知識(shí)有一個(gè)更加形象的理解,向你展示這個(gè)美麗而神秘的C++世界,讓你在有趣的看圖過(guò)程中,輕松地學(xué)到了C++知識(shí)。

            clip_image004

            看得有趣、學(xué)得輕松

            免費(fèi)下載

            posted @ 2011-07-19 11:41 陳良喬——《我的第一本C++書(shū)》 閱讀(1523) | 評(píng)論 (1)編輯 收藏

            僅列出標(biāo)題  下一頁(yè)
            日本国产精品久久| 久久婷婷人人澡人人爽人人爱| 久久精品国产72国产精福利| 久久人人青草97香蕉| 久久精品麻豆日日躁夜夜躁| 大香网伊人久久综合网2020| 国产亚洲精品久久久久秋霞| 国产成人99久久亚洲综合精品| 久久国产香蕉视频| 久久亚洲精品无码aⅴ大香| 精品久久香蕉国产线看观看亚洲| 热综合一本伊人久久精品| 狠狠色丁香久久婷婷综合_中| 无码精品久久久天天影视| 国产色综合久久无码有码| 国产精品欧美久久久天天影视| 伊人久久大香线蕉av不卡| 国产精品视频久久| 久久久高清免费视频| 亚洲国产天堂久久综合网站| 久久久久综合网久久| 精品国产91久久久久久久| 伊人久久精品影院| 久久久久这里只有精品 | 久久亚洲精品国产精品| 免费久久人人爽人人爽av| 色噜噜狠狠先锋影音久久| 久久亚洲精品无码AV红樱桃| 色播久久人人爽人人爽人人片aV| 91精品国产高清久久久久久91| 久久综合噜噜激激的五月天| 久久中文字幕人妻熟av女| 亚洲国产小视频精品久久久三级| 久久精品国产色蜜蜜麻豆 | 无码人妻少妇久久中文字幕| 久久精品国产一区| 成人久久久观看免费毛片| 久久99精品综合国产首页| 久久精品99久久香蕉国产色戒 | 久久强奷乱码老熟女网站| 99久久www免费人成精品|