整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          小升初英語分冊詞匯總表(帶音標(biāo))



          二冊

          I am (我)是[?m]

          come in. 進(jìn)來[k?m]

          good morning! 早上好!

          from beijing 從北京來的

          at the zoo 在動物園里

          factory工廠['f?kt?ri]

          capital首都['k?pit?l]

          the capital of China 中國的首都 motherland 祖國['m?e?l?nd]

          our我們的['au?] national國家的['n???n?l]

          national flag國旗[fl?ɡ]

          Chinese 中國的;漢語;中國人['t?ai'ni:z]

          English英國的;英語;英國人['i?gli?]

          over there 在那邊 American美國的,美國人[?'merik?n]

          an一(個) [?n] apple蘋果['?pl]

          hand手[h?nd] egg蛋[eɡ]

          umbrella 傘[?m'brel?] school is over. 放學(xué)了 home家[h?um]

          go home 回家 rain 雨;下雨[rein] it's raining. 正在下雨

          can't 不能 now 現(xiàn)在[nau] much許多[m?t?]

          how much 多少 eleven 十一[i'lev?n] twelve十二[twelv]

          here這兒[hi?] here you are. 給你

          they 他(她,它)們 twenty 二十['twenti]

          these 這些[ei:z] those 那些[e?uz] door 門[d?:]

          picture圖畫['pikt??] talk說話,談?wù)揫t?:k]

          flower花['flau?] some 一些[s?m]

          boat 船[b?ut] lake 湖[leik] skirt 裙子[sk?:t]

          clean 清潔的[kli:n] shirt (男式)襯衫[??:t]

          cup 杯子[k?p] glass玻璃杯[ɡlɑ:s] picture-book 圖畫書

          have a look 看一看 sure 當(dāng)然,一定[?u?] and和[?nd]

          grade 年級[ɡreid] maths數(shù)學(xué)[m?θs] your 你們的[j?: ]

          their 他(她,它)們的 [eε?] pioneer 先鋒[,pai?'ni?]

          young pioneer 少年先鋒隊(duì)員 scarf 領(lǐng)巾[skɑ:f] red scarf 紅領(lǐng)巾

          both 兩[b?uθ] all全部,都[?:l] peasant農(nóng)民['pez?nt]

          soldier士兵['s?uld??] class is over下課了

          play 玩[plei] there are 有 do做du: ]

          what are they doing? 她們在做什么?pingpong 乒乓 right對的[rait]

          join 參加[d??in] them 他(她,它)們(賓格) [eem]

          第三冊

          piece片[pi:s] a piece of 一片,一張

          ink墨水[i?k] bottle瓶['b?tl] a bottle of 一瓶

          bread面包[bred] give給[ɡiv]

          me我(賓格) [mi: ] please請[pli:z] thank謝謝[θ??k]

          want要[w?:nt] write寫[rait]

          any任何['eni] have you any paper? 你有紙嗎? Thanks謝謝

          go去[ɡ?u] go to the door 到門那兒去 open開 ['?up?n]

          close關(guān)[kl?uz] blackboard黑板 ['bl?kb?:d]

          clean把…弄干凈[kli:n] football足球 ['fut,b?:l]

          match比賽[m?t?] this afternoon今天下午 [,ɑ:ft?:'nu:n]

          time時候[taim] what time? 什么時候?

          at three 在三時 but但是[b?t] jacket外衣,夾克['d??kit]

          basketball籃球['bɑ:skitb?:l] TV電視 radio 收音機(jī)['reidi?u]

          bat球拍[b?t] maybe也許,可能['meibi] of course 當(dāng)然[k?:s]

          some一些[s?m] knife小刀[naif] sorry對不起,抱歉

          for為[ f?: ] can能夠[k?n] make做,制作[meik]

          right now立刻 there is有,存在 picture圖畫 ['pikt??]

          near 靠近[ni?] playground操場['pleiɡraund] model模型['m?d?l]

          model plane模型飛機(jī) model ship 模型輪船 sky天空 [skai]

          lake湖[leik] bright明亮的[brait] above 在…上方[?'b?v]

          slogan標(biāo)語,口號['sl?uɡ?n] world世界[w?:ld] many許多['meni]

          lesson功課 ['les?n] have lessons上課 like喜歡[laik]

          table桌子['teibl] let讓[let] us 我們(賓格) [?s]

          have a look 看一看 toy玩具[t?i] fly飛[flai]

          house房子[haus] tree 樹[tri:] river河流 ['riv?]

          dog狗[[d?ɡ] front前面,前部[fr?nt] in front of 在…前面

          cat貓[k?t] then那么,然后[een] cow母牛[kau]

          behind在..后面[bi'haind] goose鵝[ɡu:s] geese鵝(復(fù)數(shù)) [ɡi:s]

          moon月亮[mu:n] air 空氣[ε?] mountain山['mauntin]

          think想,認(rèn)為[θi?k] so這樣,這么,所以['s?u]

          animal動物['?nim?l] life 生命,生活[laif] which 哪一個 [hwit?]

          nineteen十九[,nain'ti:n] twenty二十['twenti] thirty 三十['θ?:ti]

          twenty-one二十一['twenti'w?n] thirty-three三十三['θ?:ti'θri:]

          miss 女士,小姐[mis] people 人,人民['pi:pl] family家,家庭['f?mili]

          day白天[dei] week周,星期[wi:k] today今天[t?'dei]

          baby嬰兒,幼畜['beibi] see看見[si:] zebra斑馬['zi:br?]

          monkey猴子['m??ki] run跑[r?n] jump跳[d??mp]

          all the time 一直 count數(shù)[kaunt] lion獅子['lai?n]

          tiger 老虎['taiɡ?] sit坐[sit] exercise練習(xí)['eks?saiz]

          exercise-book 練習(xí)本 out出,在外[aut] out of 向(在)…外面

          listen聽['lis?n] read讀[ri:d] after在…后面 ['ɑ:ft?]

          stop停止[st?p] wait 等待[weit] evening傍晚,晚上['i:vni?]

          cinema電影院['sin?m?] crossing 十字路口['kr?:si?] light 燈,光['lait]

          must必須,應(yīng)該[m?st] yet還(沒有)…還(不)…[jet] o'clock 點(diǎn)鐘[?'kl?k]

          morning早晨,上午['m?:ni?] get得到[ɡet] up向上[?p]

          get up起床 half半[hɑ:f, h?f] past過[pɑ:st, p?st]

          morning exercises早操 breakfast早餐['brekf?st] eye-exercises 眼保操

          have a lesson上課 draw畫[dr?:] clock鐘[kl?k]

          tell 告訴[tel] her 她(賓格) [h?: ] stand站,站立[st?nd]

          ask 問,提問[ɑ:sk] question問題['kwest??n] other別的['?e?]

          answer 回答['ɑ:ns?] talk in English 用英語交談 help 幫助[help]

          quarter四分之一;一刻['kw?:t?] game游戲[ɡeim] study學(xué)習(xí),研究['st?di]

          supper晚飯['s?p?] watch觀看 [w?:t?] homework家庭作業(yè)['h?umw?:k]

          Mr.先生(mister的縮寫) ['mist?] son兒子[s?n] daughter女兒['d?:t?]

          newspaper報(bào)紙['nju:s,peip?] by 在…旁,靠近 story故事['st?:ri]

          story-book故事書 with和…用…[wie] play with 玩…

          sweep掃[swi:p] floor地板,地面[fl?:] mop擦,抹,拖[m?p]

          ready準(zhǔn)備好了['redi] still 還,仍舊[stil] lunch午餐[l?nt?]

          room房間[ru:m] look for 尋找 hurry匆忙,趕緊 ['h?ri]

          hurry up! 快點(diǎn)! fox狐貍[f?ks] news消息,新聞[nju:z]

          down向下[daun] very很,非常['veri] way路[wei]

          come this way 往這邊來 well健康的[wel] away離[?'wei]

          run away 跑掉 why (表吃驚,滿意等)哎呀!為什么?[hwai]

          第四冊

          board 寫字板 [b?:d] computer 計(jì)算機(jī) teacher's desk 講臺

          fan扇子,電扇[f?n] classmate同學(xué)['klɑ:smeit] good idea好主意[ai'di?]

          all right好吧,好的 seat座位[si:t] good job 干的好[d??b]

          what什么[hw?t] look at 看…… Chinese book 語文書

          English book 英語書 notebook 筆記本['n?utbuk] too many 太多了

          fat胖的[f?t] heavy重的;沉重的['hevi] may可以[mei]

          long hair 長頭發(fā)[hε?] short hair 短頭發(fā) thin 瘦的[θin]

          strong 健壯的[str?? quiet 安靜的['kwai?t] his 他的[hiz]

          photo 照片['f?ut?u] teacher 教師['ti:t??] student 學(xué)生['stju:d?nt]

          music音樂['mju:zik] science科學(xué)['sai?ns] sports 體育運(yùn)動[sp?:ts]

          電腦游戲 painting 繪畫['peinti?] boy 男孩[b?i]

          girl女孩[ɡ?:l] bathroom 衛(wèi)生間['bɑ:θrum] bedroom 臥室['bedrum]

          kitchen 廚房['kit?in] 冰箱[frid?] key鑰匙[ki:]

          desk 課桌;書桌[desk] rice米飯[rais] noodle(s) 面條['nu:dl]

          beef 牛肉[bi:f] vegetable 蔬菜['ved?it?bl] soup 湯[su:p]

          hungry饑餓的['h??ɡri] 筷子()['t??pstiks]

          spoon 勺子[spu:n] plate 盤子[pleit] fork 叉子[f?:k]

          pass 傳遞[pɑ:s] try試一下[trai] 隨便吃

          show 展示[??u] food 食物[fu:d] parents 父母['p??r?nts]

          uncle 叔叔;舅舅['??kl] aunt 姑姑;嬸;姨[ɑ:nt] member 成員['memb?]

          only 只有;僅僅['?unli] puppy 小狗['p?pi] sister 姐妹['sist?]

          brother 兄弟['br?e?] father 父親;爸爸['fɑ:e?] driver 司機(jī)[draiv?]

          farmer 農(nóng)民['fɑ:m?] nurse 護(hù)士[n?:s] it 它 [it]

          class 課程[klɑ:s] dress 連衣裙[dres] T-shirt T恤衫

          no 不;不是[n?u] not 不;不是的[n?t] warm 暖和的[w?:m]

          cold 寒冷的[k?uld] cool 涼爽的[ku:l] today 今天[t?'dei]

          jean 牛仔褲[d?ein] pant 長褲[p?nt] socks 襪子[s?ks]

          shoes 鞋子[?u:s] snowy 下雪的['sn?ui] 晴朗的['s?ni]

          banana 香蕉[b?'nɑ:n?] pear梨[pε?] 西瓜['w?:t?mel?n

          they她們[eei] horse 馬[h?:s] Monday 星期一['m?ndi]

          Tuesday星期二 ['tju:zdi ] Wednesday星期三['wenzdei ] Thursday ] 星期四['θ?:zdi]

          Friday星期五 ['fraidi] Saturday星期六 ['s?t?di] Sunday星期天 ['s?ndi]

          第五冊

          robot 機(jī)器人['r?b?t] good 好的[g?d] friend朋友[frend]

          hear 聽,聽見[hi?] work工作[w?:k] walk 走路,步行[w?:k]

          excuse me. 對不起!請?jiān)彛iks'kju:z] take 拿,乘[teik] number 號,號碼['n?mb?]

          take a no.7 bus 乘七路公共汽車 trolley-bus 無軌電車['tr?lib?s]

          underground. 地下火車,地鐵['?nd?graund

          by underground 乘地鐵 bus stop 公共汽車站[st?p] catch 趕上;抓住[k?t?]

          fish 魚[fi?] bird鳥[b?:d fly飛[flai] swim 游泳[swim]

          so這樣,這么,所以 sing 唱,唱歌[si?] dance跳舞,舞蹈['dɑ:ns]

          speak 說[spi:k] little少許,一點(diǎn)點(diǎn)['litl] a little 少許,一點(diǎn)點(diǎn)

          owl 貓頭鷹[?ul] each每個各自的[i:t?] each other 互相['?e?]

          begin 開始[bi'gin] much 許多;很,非常[m?t?] like像[laik]

          so much like 很像 dark 黑暗[dɑ:k] say說sei]

          after all 究竟,到底 sometimes 有時候['s?mtaimz] go to bed 去睡覺

          after school 放學(xué)后 often 經(jīng)常,常常'?:ft?n] child小孩[t?aild]

          children 小孩(復(fù)數(shù)) ['t?ildr?n] palace宮殿['p?lis] a lot of 許多…

          fun樂趣,娛樂[f?n] every每個的['evri] early早,早的['?:li]

          wash洗[w??] brush刷(子) [br??] tooth 牙[tu:θ]

          teeth牙(復(fù)數(shù)) [ti:θ] about 關(guān)于;大約['?baut] far遠(yuǎn)[fɑ:]

          usually通常['ju:???li] want想要,需要[w?nt] summer夏天['s?m?]

          winter冬季,冬天['wint?] skate 滑冰[skeit ] buy買[bai]

          size 大小,尺寸,號碼[saiz] try試[trai] try on 試穿

          will將[wil] hare野兔[h??] tortoise烏龜['t?:t?s]

          race比賽[reis] have a race 賽一賽 get到達(dá)[get]

          get there 到那里 got (動詞get的過去式) [g?t]

          first第一,首先[f?:st] win贏,獲勝[win] rest休息[rest]

          sleep 睡覺[sli:p] fast 快[fɑ:st] Russian俄語,俄國人['r???n]

          volleyball排球['v?lib?:l] Mr. and Mrs. white 懷特先生和夫人

          England英國['ingl?nd] America美國;美洲[?'merik?]

          welcome歡迎;受歡迎的['welk?m] how do you do? (初次見面)您好!

          forty四十['f?:ti] forty-two四十二 very much 非常

          only僅僅唯一的['?unli] bell鈴,鈴聲[bel] it's time for 是…的時候了

          back后面[b?k] at the back 在后面 when什么時候[(h)wen]

          begin classes 開始上課 time次,次數(shù)[taim] month月[m?nθ]

          once一次[w?ns] once a week 每周一次 group 組[gru:p]

          pool 池[pu:l] swimming-pool 游泳池 man男子[m?n]

          him他(賓格) [him] woman婦女['wum?n] her 她(賓格) [h? ]

          bring帶來,拿來[bri?] us 我們(賓格) call 叫[k?:l]

          dad 爸爸[d?d] cabbage卷心菜 ['k?bid?] pair 一雙[p??]

          a pair of 一雙… shoe 鞋[?u:] yours你的,你們的[ju?z]

          mine我的[main] whose 誰的[hu:z] trousers 褲子,長褲['tra?z?z]

          a pair of trousers 一條褲子 ours 我們的['au?z] other另外的['?e?]

          theirs他(她,它)們的[e??z] wear 穿戴[wε?] blouse (女式)襯衫[blauz]

          hers 她的[h?:z] ground地面[gra?nd] pick 采,摘[pik]

          pick up 拾起 empty 空的['empti] basin 盆,臉盆['beis?n]

          put 放into 到…里 really 真地['ri?li] may i have a try? 我可以試試嗎?

          第六冊

          do morning exercises 晨練['m?:ni?] ['eks?saiz] eat breakfast 吃早飯[i:t] ['brekf?st]

          have English class上英語課[h?v ] ['i?gli?] [klɑ:s] play sports進(jìn)行體育運(yùn)動[plei] [sp?:ts]

          eat dinner 吃晚飯['din?] when 什么時候[(h)wen] evening 夜晚;晚上['i:vni?]

          get up 起床[get] [?p] usually 通常;一般['ju:???li] noon 中午[nu:n]

          climb mountains 爬山[klaim] ['mauntins] go shopping 購物;買東西[g?u] ['??pi?]

          play the piano彈鋼琴[plei] [pi'ɑ:n?u ]visit grandparents看望祖父母['vizit] ['gr?n,p??r?nts]

          go hiking 去遠(yuǎn)足['haiki?] 周末['wi:kend] often 經(jīng)常['?:ft?n]

          sometimes 有時候['s?mtaimz] spring 春天[spri?] summer 夏天['s?m?]

          fall 秋天[f?:l] winter 冬天['wint?] season 季節(jié)['si:zn]

          which 哪一個[(h)wit?] best 最;極[best] swim 游泳[swim]

          fly kites 放風(fēng)箏[flai] [kait] skate 滑冰(鞋)[skeit] make a snowman 堆雪人['sn??m?n]

          plant trees 種樹[plɑ:nt] [tri:s] because 因?yàn)閇bi'k?z] sleep 睡覺[sli:p]

          生日['b?:θdei] date 日期[deit] draw pictures 畫畫[dr?:] ['pikt??z]

          cook dinner做飯[kuk] ['din?] read a book 看書[rid] answer the phone 接電話['ɑ:ns?] [f?un]

          listen to music聽音樂['lisn] ['mju:zik] clean the room打掃房間[kli:n][rum]

          write a letter寫信[rait] ['let?]write an 寫電子郵件 grandpa 爺爺;外公['gr?ndpɑ:]

          study 書房['st?di] 袋鼠[,k??g?'ru:] sleep 睡覺[sli:p]

          climb 往上爬[klaim] fight 打架[fait] swing 蕩;蕩秋千[swi?]

          drink water 喝水[dri?k] ['w?:t?] 照相[teik] ['pikt??z]

          watch insects 觀察昆蟲[w?t?] ['insekt] pick up leaves 采摘樹葉[pik] [?p] [li:vz]

          do an experiment [du:] [?n] [iks'perim?nt] 做實(shí)驗(yàn) catch butterfly 捉蝴蝶[k?t?] ['b?t?flai]

          honey蜂蜜['h?ni] count insects 數(shù)昆蟲[ka?nt] ['insekt] collect leaves 收集樹葉[k?'lekt]

          write a report寫報(bào)告[rait][ri'p?:t] play chess下棋[plei][t?es] 舉行野餐['piknik]

          第七冊

          traffic 交通['tr?fik] 交通燈[lait] traffic rule交通規(guī)則ru:l]

          stop 停,停車站[st?p] wait 等待[weit] get to 到達(dá)[get] [tu]

          library 圖書館['laibr?ri] post office 郵局[p??st] ['?fis] hospital 醫(yī)院['h?spitl]

          cinema電影院['sinim?] bookstore 書店['bukst?:] where 在哪里,到哪里[(h)w??]

          please 請[pli:z] 與……相鄰[nekst] turn 轉(zhuǎn)彎t?:n]

          right 右邊[rait] left 左邊[left] straight 成直線地[streit]

          then 然后[een] next week 下周[wi:k] 今天上午[eis] ['m?:ni?]

          this afternoon 今天下午[eis] ['ɑ:ft?'nu:n] this evening今天晚上[eis] ['i:vni?]

          comic book 漫畫書['k?mik] [buk] comic連環(huán)圖畫,喜劇的['k?mik]

          post card 明信片[p??st] [kɑ:d] hobby 愛好['h?bi]

          ride a bike→riding a bike 騎自行車[raid] dive→diving 跳水[daiv]

          play the violin→playing the violin 拉小提琴['pleii?] [,vai?'lin] go→goes 去[g??z]

          make kites→making kites 制作風(fēng)箏[meik] [kait] live→lives 居住[liv ] [laivz]

          teach→teaches 教[ti:t?] collect stamps→collecting stamps 集郵[k?'lekt] [st?mps]

          watch→watches看[w?t?] read→reads 讀,看[rid] doesn't=does not [d?z ]

          singer 歌唱家,歌手['sind??] writer 作家['rait?] actor 男演員['?kt?]

          actress女演員['?ktris] artist 畫家['ɑ:tist] TV reporter 電視臺記者[ri'p?:t?]

          engineer工程師[,end?i'ni?] accountant會計(jì)[?'kaunt?nt] policeman 男警察[p?'li:sm?n]

          salesperson銷售員['seilz,p?:s?n] cleaner清潔工['kli:n?] work 工作[w?:k]

          cloud 云[klaud] sun 太陽[s?n] stream 河,溪[stri:m] 來自k?m] [fr?m ]

          seed 種子[si:d] soil 土壤[s?il] sprout 苗,芽[spraut] plant 植物,種植[plɑ:nt]

          should 應(yīng)該[?ud ] then 然后[een]

          第八冊

          tall → taller更高的[t?:l] short → shorter 更矮的[??:t] strong → stronger 更強(qiáng)壯的[str??]

          old → older 年齡更大的[?uld] young → younger 更年輕的[j??] big → bigger 更大的[big]

          heavy → heavier 更重的['hi:vi] long → longer 更長的[l??] thin → thinner 更瘦的[θin]

          small → smaller 體型更小的[sm?:l] have a fever 發(fā)燒[h?v] ['fi:v?]

          have a sore throat 喉嚨疼[ s?, s??] [θr?ut] have a cold 感冒[k?uld

          have a toothache 牙疼['tu:θeik] 頭疼['hedeik]

          matter 事情,麻煩'm?t?] sore 疼的[ s? ] hurt 疼痛[h?:t]

          tired 疲勞的,累的['tai?d] excited 興奮的[ik'saitid] angry 生氣的['??gri]

          happy 高興的['h?pi] bored 無聊的,煩人的[b?:d] sad 憂傷的,悲傷的[s?d]

          watch → watched 看[w?t? wash → washed 洗[w??t] clean → cleaned 打掃[kli:n]

          play → played 玩[plei] visit → visited 看望['vizit]do → did last weekend 上一個周末 go → went 去[g?u] [went] go to a park → went to a park 去公園[pɑ:k]

          go swimming→went swimmin去游泳['swimi?] go fishing → went fishing 去釣魚['fi?i?]

          hiking徒步旅行['haiki?] go hiking → went hiking 去郊游['haiki?]

          learn Chinese → learned Chinese 學(xué)漢語[l?:n] ['t?ai'ni:z] ['l?:nid]

          → sang and danced 唱歌和跳舞[si?] ['dɑ:ns] s??]

          eat good food → ate good food 吃好吃的食物[i:t] [g?d] [fu:d] [et]

          take pictures → took pictures 照相[teik] [tuk] climb → climbed 爬klaim]

          had buy presents → bought presents 買禮物[h?d] [bai] [pri'zent] [ b?:t]

          row劃,劃船,責(zé)罵[rau] row a boat → rowed a boat 劃船[rau] [b?ut]

          see elephant → saw elephant 看大象[si:] ['elif?nt] [s?:]

          ski滑雪,雪橇[ski go skiing → went skiing 去滑雪[ 'ski:i?] skate溜冰,滑冰[skeit, skit]

          go ice-skating → went ice-skating 去滑冰[ais] how 怎么,如何[hau]

          get → got 到達(dá)[get] [g?t] last 上一個的,僅余的,留在最后的[lɑ:st]

          者 | fengbingchun

          責(zé)編 | 屠敏

          出品 | CSDN 博客

          Scott Meyers大師Effective三部曲:Effective C++、More Effective C++、Effective STL,這三本書出版已很多年,后來又出版了Effective Modern C++。

          這里是More Effective C++的筆記:

          1. 指針與引用的區(qū)別

          void printDouble(const double& rd)
          {
          std::cout<<rd; // 不需要測試rd,它肯定指向一個double值
          }

          voidprintDouble(const double* pd)
          {
          if (pd) { // 檢查是否為
          std::cout<<*pd;
          }
          }

          inttest_item_1
          {
          char* pc = 0; // 設(shè)置指針為空值
          char& rc = *pc; // 讓指針指向空值,這是非常有害的,結(jié)果將是不確定的

          //std::string& rs; // 錯誤,引用必須被初始化
          std::strings("xyzzy");
          std::string& rs = s; // 正確,rs指向s
          std::string* ps; // 未初始化的指針,合法但危險(xiǎn)

          {
          std::strings1("Nancy");
          std::strings2("Clancy");
          std::string& rs = s1; // rs引用s1
          std::string* ps = &s1; // ps指向s1
          rs = s2; // rs仍舊引用s1,但是s1的值現(xiàn)在是"Clancy"
          ps = &s2; // ps現(xiàn)在指向s2,s1沒有改變
          }

          std::vector<int> v(10);
          v[5] = 10; // 這個被賦值的目標(biāo)對象就是操作符返回的值,如果操作符
          // 返回一個指針,那么后一個語句就得這樣寫: *v[5] = 10;

          return 0;
          }

          指針與引用看上去完全不同(指針用操作符”*”和”->”,引用使用操作符”.”),但是它們似乎有相同的功能。指針和引用都是讓你間接引用其它對象。

          在任何情況下都不能使用指向空值的引用。一個引用必須總是指向某些對象。在C++里,引用應(yīng)被初始化。

          不存在指向空值的引用這個事實(shí)意味著使用引用的代碼效率比使用指針的要高。因?yàn)樵谑褂靡弥安恍枰獪y試它的合法性。

          指針與引用的另一個重要的不同是指針可以被重新賦值以指向另一個不同的對象。但是引用則總是指向在初始化時被指定的對象,以后不能改變。

          總的來說,在以下情況下你應(yīng)該使用指針,一是你考慮到存在不指向任何對象的可能(在這種情況下,你能夠設(shè)置指針為空),二是你需要能夠在不同的時刻指向不同的對象(在這種情況下,你能改變指針的指向)。如果總是指向一個對象并且一旦指向一個對象后就不會改變指向,那么你應(yīng)該使用引用。

          當(dāng)你知道你必須指向一個對象并且不想改變其指向時,或者在重載操作符并為防止不必要的語義誤解時(最普通的例子是操作符[]),你不應(yīng)該使用指針。而在除此之外的其它情況下,則應(yīng)使用指針。

          關(guān)于引用的更多介紹參考:https://blog.csdn.net/fengbingchun/article/details/69820184

          2. 盡量使用C++風(fēng)格的類型轉(zhuǎn)換

          class Widget {
          public:
          virtual voidfunc {}
          };

          class SpecialWidget : public Widget {
          public:
          virtual voidfunc {}
          };

          voidupdate(SpecialWidget* psw) {}
          voidupdateViaRef(SpecialWidget& rsw) {}

          typedef void(*FuncPtr); // FuncPtr是一個指向函數(shù)的指針
          intdoSomething { return 1; };

          inttest_item_2
          {
          int firstNumber = 1, secondNumber = 1;
          double result1 = ((double)firstNumber) / secondNumber; // C風(fēng)格
          double result2 = static_cast<double>(firstNumber) / secondNumber; // C++風(fēng)格類型轉(zhuǎn)換

          SpecialWidget sw; // sw是一個非const對象
          const SpecialWidget& csw = sw; // csw是sw的一個引用,它是一個const對象
          //update(&csw); // 錯誤,不能傳遞一個const SpecialWidget*變量給一個處理SpecialWidget*類型變量的函數(shù)
          update(const_cast<SpecialWidget*>(&csw)); // 正確,csw的const顯示地轉(zhuǎn)換掉(csw和sw兩個變量值在update函數(shù)中能被更新)
          update((SpecialWidget*)&csw); // 同上,但用了一個更難識別的C風(fēng)格的類型轉(zhuǎn)換

          Widget* pw = new SpecialWidget;
          //update(pw); // 錯誤,pw的類型是Widget*,但是update函數(shù)處理的是SpecialWidget*類型
          //update(const_cast<SpecialWidget*>(pw)); // 錯誤,const_cast僅能被用在影響constness or volatileness的地方,不能用在向繼承子類進(jìn)行類型轉(zhuǎn)換

          Widget* pw2 = ptr;
          update(dynamic_cast<SpecialWidget*>(pw2)); // 正確,傳遞給update函數(shù)一個指針是指向變量類型為SpecialWidget的pw2的指針, 如果pw2確實(shí)指向一個對象,否則傳遞過去的將是空指針

          Widget* pw3 = new SpecialWidget;
          updateViaRef(dynamic_cast<SpecialWidget&>(*pw3)); // 正確,傳遞給updateViaRef函數(shù)SpecailWidget pw3指針,如果pw3確實(shí)指向了某個對象,否則將拋出異常

          //double result3 = dynamic_cast<double>(firstNumber) / secondNumber; // 錯誤,沒有繼承關(guān)系
          const SpecialWidget sw4;
          //update(dynamic_cast<SpecialWidget*>(&sw4)); // 錯誤,dynamic_cast不能轉(zhuǎn)換掉const

          FuncPtr funcPtrArray[10]; // funcPtrArray是一個能容納10個FuncPtr指針的數(shù)組
          //funcPtrArray[0] = &doSomething; // 錯誤,類型不匹配
          funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // 轉(zhuǎn)換函數(shù)指針的代碼是不可移植的(C++不保證所有的函數(shù)指針都被用一樣的方法表示),在一些情況下這樣的轉(zhuǎn)換會產(chǎn)生不正確的結(jié)果,所以應(yīng)該避免轉(zhuǎn)換函數(shù)指針類型

          return 0;
          }

          C++通過引進(jìn)四個新的類型轉(zhuǎn)換(cast)操作符克服了C風(fēng)格類型轉(zhuǎn)換的缺點(diǎn)(過于粗魯,能允許你在任何類型之間進(jìn)行轉(zhuǎn)換;C風(fēng)格的類型轉(zhuǎn)換在程序語句中難以識別),這四個操作符是:static_cast、const_cast、dynamic_cast、reinterpret_cast。

          static_cast在功能上基本上與C風(fēng)格的類型轉(zhuǎn)換一樣強(qiáng)大,含義也一樣。它也有功能上限制。例如,不能用static_cast像用C 風(fēng)格的類型轉(zhuǎn)換一樣把struct轉(zhuǎn)換成int類型或者把double類型轉(zhuǎn)換成指針類型,另外,static_cast不能從表達(dá)式中去除const屬性,因?yàn)榱硪粋€新的類型轉(zhuǎn)換操作符const_cast有這樣的功能。

          const_cast用于類型轉(zhuǎn)換掉表達(dá)式的const或volatileness屬性。如果你試圖使用const_cast來完成修改constness或者volatileness屬性之外的事情,你的類型轉(zhuǎn)換將被拒絕。

          dynamic_cast被用于安全地沿著類的繼承關(guān)系向下進(jìn)行類型轉(zhuǎn)換。這就是說,你能用dynamic_cast把指向基類的指針或引用轉(zhuǎn)換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉(zhuǎn)換是否成功。失敗的轉(zhuǎn)換將返回空指針(當(dāng)對指針進(jìn)行類型轉(zhuǎn)換時)或者拋出異常(當(dāng)對引用進(jìn)行類型轉(zhuǎn)換時)。dynamic_cast在幫助你瀏覽繼承層次上是有限制的,它不能被用來缺乏虛函數(shù)的類型上,也不能用它來轉(zhuǎn)換掉constness。如你想在沒有繼承關(guān)系的類型中進(jìn)行轉(zhuǎn)換,你可能想到static_cast。如果是為了去除const,你總得用const_cast。

          reinterpret_cast使用這個操作符的類型轉(zhuǎn)換,其轉(zhuǎn)換結(jié)果幾乎都是執(zhí)行期定義(implementation-defined)。因此,使用reinterpret_cast的代碼很難移植。此操作符最普通的用途就是在函數(shù)指針之間進(jìn)行轉(zhuǎn)換。

          關(guān)于類型轉(zhuǎn)換更多介紹參考:https://blog.csdn.net/fengbingchun/article/details/51235498

          3. 不要對數(shù)組使用多態(tài)

          class BST {
          public:
          virtual ~BST { fprintf(stdout, "BST::~BST\n"); }
          private:
          int score;
          };

          class BalancedBST : public BST {
          public:
          virtual ~BalancedBST { fprintf(stdout, "BalancedBST::~BalancedBST\n"); }
          private:
          int length;
          int size; // 如果增加此一個int成員,執(zhí)行test_item_3會segmentation fault,注釋掉此變量,運(yùn)行正常
          };

          inttest_item_3
          {
          fprintf(stdout, "BST size: %d\n", sizeof(BST)); // 16
          fprintf(stdout, "BalancedBST size: %d\n", sizeof(BalancedBST)); // 24

          BST* p = new BalancedBST[10];
          delete p; // 如果sizeof(BST) != sizeof(BalancedBST),則會segmentation fault

          return 0;
          }

          C++允許你通過基類指針和引用來操作派生類數(shù)組。不過這根本就不是一個特性,因?yàn)檫@樣的代碼幾乎從不如你所愿地那樣運(yùn)行。數(shù)組與多態(tài)不能用在一起。值得注意的是如果你不從一個具體類(concrete classes)(例如BST)派生出另一個具體類(例如BalancedBST),那么你就不太可能犯這種使用多態(tài)性數(shù)組的錯誤。

          4. 避免無用的缺省構(gòu)造函數(shù)

          class EquipmentPiece {
          public:
          EquipmentPiece(int IDNumber) {}
          };

          inttest_item_4
          {
          //EquipmentPiece bestPieces[10]; // 錯誤,沒有正確調(diào)用EquipmentPiece構(gòu)造函數(shù)
          //EquipmentPiece* bestPieces2 = new EquipmentPiece[10]; // 錯誤,與上面的問題一樣

          int ID1 = 1, ID2 = 2;
          EquipmentPiece bestPieces3 = { EquipmentPiece(ID1), EquipmentPiece(ID2) }; // 正確,提供了構(gòu)造函數(shù)的參數(shù)

          // 利用指針數(shù)組來代替一個對象數(shù)組
          typedef EquipmentPiece* PEP; // PEP指針指向一個EquipmentPiece對象
          PEP bestPieces4[10]; // 正確,沒有調(diào)用構(gòu)造函數(shù)
          PEP* bestPieces5 = new PEP[10]; // 也正確
          // 在指針數(shù)組里的每一個指針被重新賦值,以指向一個不同的EquipmentPiece對象
          for (int i = 0; i < 10; ++i)
          bestPieces5[i] = new EquipmentPiece(ID1);

          // 為數(shù)組分配raw memory,可以避免浪費(fèi)內(nèi)存,使用placement new方法在內(nèi)存中構(gòu)造EquipmentPiece對象
          void* rawMemory = operator new(10*sizeof(EquipmentPiece));
          // make bestPieces6 point to it so it can be treated as an EquipmentPiece array
          EquipmentPiece* bestPieces6 = static_cast<EquipmentPiece*>(rawMemory);
          // construct the EquipmentPiece objects in the memory使用"placement new"
          for (int i = 0; i < 10; ++i)
          new(&bestPieces6[i]) EquipmentPiece(ID1);
          // ...
          // 以與構(gòu)造bestPieces6對象相反的順序解構(gòu)它
          for (int i = 9; i >= 0; --i)
          bestPieces6[i].~EquipmentPiece; // 如果使用普通的數(shù)組刪除方法,程序的運(yùn)行將是不可預(yù)測的
          // deallocate the raw memory
          delete rawMemory;

          return 0;
          }

          構(gòu)造函數(shù)能初始化對象,而缺省構(gòu)造函數(shù)則可以不利用任何在建立對象時的外部數(shù)據(jù)就能初始化對象。有時這樣的方法是不錯的。例如一些行為特性與數(shù)字相仿的對象被初始化為空值或不確定的值也是合理的,還有比如鏈表、哈希表、圖等等數(shù)據(jù)結(jié)構(gòu)也可以被初始化為空容器。但不是所有的對象都屬于上述類型,對于很多對象來說,不利用外部數(shù)據(jù)進(jìn)行完全的初始化是不合理的。比如一個沒有輸入姓名的地址薄對象,就沒有任何意義。

          利用指針數(shù)組代替一個對象數(shù)組這種方法有兩個缺點(diǎn):第一你必須刪除數(shù)組里每個指針?biāo)赶虻膶ο蟆H绻耍蜁l(fā)生內(nèi)存泄漏。第二增加了內(nèi)存分配量,因?yàn)檎缒阈枰臻g來容納EquipmentPiece對象一樣,你也需要空間來容納指針。

          對于類里沒有定義缺省構(gòu)造函數(shù)還會造成它們無法在許多基于模板(template-based)的容器類里使用。因?yàn)閷?shí)例化一個模板時,模板的類型參數(shù)應(yīng)該提供一個缺省構(gòu)造函數(shù)。在多數(shù)情況下,通過仔細(xì)設(shè)計(jì)模板可以杜絕對缺省構(gòu)造函數(shù)的需求。

          5. 謹(jǐn)慎定義類型轉(zhuǎn)換函數(shù)

          class Name {
          public:
          Name(const std::string& s); // 轉(zhuǎn)換string到Name
          };

          class Rational {
          public:
          Rational(int numerator = 0, int denominator = 1) // 轉(zhuǎn)換int到有理數(shù)類
          {
          n = numerator;
          d = denominator;
          }

          operatordouble const // 轉(zhuǎn)換Rational類成double類型
          {
          return static_cast<double>(n) / d;
          }

          doubleasDouble const
          {
          return static_cast<double>(n) / d;
          }

          private:
          int n, d;
          };

          template<class T>
          class Array {
          public:
          Array(int lowBound, int highBound) {}
          explicitArray(int size) {}
          T& operator(int index) { return data[index]; }

          private:
          T* data;
          };

          bool operator== (const Array<int>& lhs, const Array<int>& rhs)
          { return false; }

          inttest_item_5
          {
          Rational r(1, 2); // r的值是1/2
          double d = 0.5 * r; // 轉(zhuǎn)換r到double,然后做乘法
          fprintf(stdout, "value: %f\n", d);

          std::cout<<r<<std::endl; // 應(yīng)該打印出"1/2",但事與愿違,是一個浮點(diǎn)數(shù),而不是一個有理數(shù),隱式類型轉(zhuǎn)換的缺點(diǎn)
          // 解決方法是不使用語法關(guān)鍵字的等同的函數(shù)來替代轉(zhuǎn)換運(yùn)算符,如增加asDouble函數(shù),去掉operator double

          Array<int> a(10);
          Array<int> b(10);
          for (int i = 0; i < 10; ++i) {
          //if (a == b[i]) {} // 如果構(gòu)造函數(shù)Array(int size)沒有explicit關(guān)鍵字,編譯器將能通過調(diào)用Array<int>構(gòu)造函數(shù)能轉(zhuǎn)換int類型到Array<int>類型,這個構(gòu)造函數(shù)只有一個int類型的參數(shù),加上explicit關(guān)鍵字則可避免隱式轉(zhuǎn)換

          if (a == Array<int>(b[i])) {} // 正確,顯示從int到Array<int>轉(zhuǎn)換(但是代碼的邏輯不合理)
          if (a == static_cast<Array<int>>(b[i])) {} // 同樣正確,同樣不合理
          if (a == (Array<int>)b[i]) {} // C風(fēng)格的轉(zhuǎn)換也正確,但是邏輯依舊不合理
          }
          return 0;
          }

          C++編譯器能夠在兩種數(shù)據(jù)類型之間進(jìn)行隱式轉(zhuǎn)換(implicit conversions),它繼承了C語言的轉(zhuǎn)換方法,例如允許把char隱式轉(zhuǎn)換為int和從short隱式轉(zhuǎn)換為double。你對這些類型轉(zhuǎn)換是無能為力的,因?yàn)樗鼈兪钦Z言本身的特性。不過當(dāng)你增加自己的類型時,你就可以有更多的控制力,因?yàn)槟隳苓x擇是否提供函數(shù)讓編譯器進(jìn)行隱式類型轉(zhuǎn)換。

          有兩種函數(shù)允許編譯器進(jìn)行這些的轉(zhuǎn)換:單參數(shù)構(gòu)造函數(shù)(single-argument constructors)和隱式類型轉(zhuǎn)換運(yùn)算符。單參數(shù)構(gòu)造函數(shù)是指只用一個參數(shù)即可調(diào)用的構(gòu)造函數(shù)。該函數(shù)可以是只定義了一個參數(shù),也可以是雖定義了多個參數(shù)但第一個參數(shù)以后的所有參數(shù)都有缺省值。

          隱式類型轉(zhuǎn)換運(yùn)算符只是一個樣子奇怪的成員函數(shù):operator關(guān)鍵字,其后跟一個類型符號。你不用定義函數(shù)的返回類型,因?yàn)榉祷仡愋途褪沁@個函數(shù)的名字。

          explicit關(guān)鍵字是為了解決隱式類型轉(zhuǎn)換而特別引入的這個特性。如果構(gòu)造函數(shù)用explicit聲明,編譯器會拒絕為了隱式類型轉(zhuǎn)換而調(diào)用構(gòu)造函數(shù)。顯式類型轉(zhuǎn)換依然合法。

          6. 自增(increment)、自減(decrement)操作符前綴形式與后綴形式的區(qū)別

          class UPInt { // unlimited precision int
          public:
          // 注意:前綴與后綴形式返回值類型是不同的,前綴形式返回一個引用,后綴形式返回一個const類型
          UPInt& operator++ // ++前綴
          {
          //*this += 1; // 增加
          i += 1;
          return *this; // 取回值
          }

          const UPInt operator++(int) // ++后綴
          {
          // 注意:建立了一個顯示的臨時對象,這個臨時對象必須被構(gòu)造并在最后被析構(gòu),前綴沒有這樣的臨時對象
          UPInt oldValue = *this; // 取回值
          // 后綴應(yīng)該根據(jù)它們的前綴形式來實(shí)現(xiàn)
          ++(*this); // 增加
          return oldValue; // 返回被取回的值
          }

          UPInt& operator-- // --前綴
          {
          i -= 1;
          return *this;
          }

          const UPInt operator--(int) // --后綴
          {
          UPInt oldValue = *this;
          --(*this);
          return oldValue;
          }

          UPInt& operator+=(int a) // +=操作符,UPInt與int相運(yùn)算
          {
          i += a;
          return *this;
          }

          UPInt& operator-=(int a)
          {
          i -= a;
          return *this;
          }

          private:
          int i;
          };

          int test_item_6
          {
          UPInt i;
          ++i; // 調(diào)用i.operator++;
          i++; // 調(diào)用i.operator++(0);
          --i; // 調(diào)用i.operator--;
          i--; // 調(diào)用i.operator--(0);

          //i++++; // 注意:++后綴返回的是const UPInt

          return 0;
          }

          無論是increment或decrement的前綴還是后綴都只有一個參數(shù),為了解決這個語言問題,C++規(guī)定后綴形式有一個int類型參數(shù),當(dāng)函數(shù)被調(diào)用時,編譯器傳遞一個0作為int參數(shù)的值給該函數(shù)。

          前綴形式有時叫做”增加然后取回”,后綴形式叫做”取回然后增加”。

          當(dāng)處理用戶定義的類型時,盡可能地使用前綴increment,因?yàn)樗男瘦^高。

          7. 不要重載”&&”, “||”,或”,”

          int test_item_7
          {
          // if (expression1 && expression2)
          // 如果重載了操作符&&,對于編譯器來說,等同于下面代碼之一
          // if (expression1.operator&&(expression2)) // when operator&& is a member function
          // if (operator&&(expression1, expression2)) // when operator&& is a global function

          return 0;
          }

          與C一樣,C++使用布爾表達(dá)式短路求值法(short-circuit evaluation)。這表示一旦確定了布爾表達(dá)式的真假值,即使還有部分表達(dá)式?jīng)]有被測試,布爾表達(dá)式也停止運(yùn)算。

          C++允許根據(jù)用戶定義的類型,來定制&&和||操作符。方法是重載函數(shù)operator&&和operator||,你能在全局重載或每個類里重載。風(fēng)險(xiǎn):你以函數(shù)調(diào)用法替代了短路求值法。函數(shù)調(diào)用法與短路求值法是絕對不同的。首先當(dāng)函數(shù)被調(diào)用時,需要運(yùn)算其所有參數(shù)。第二是C++語言規(guī)范沒有定義函數(shù)參數(shù)的計(jì)算順序,所以沒有辦法知道表達(dá)式1與表達(dá)式2哪一個先計(jì)算。完全可能與具有從左參數(shù)到右參數(shù)計(jì)算順序的短路計(jì)算法相反。因此如果你重載&&或||,就沒有辦法提供給程序員他們所期望和使用的行為特性,所以不要重載&&和||。

          同樣的理由也適用于逗號操作符。逗號操作符用于組成表達(dá)式。一個包含逗號的表達(dá)式首先計(jì)算逗號左邊的表達(dá)式,然后計(jì)算逗號右邊的表達(dá)式;整個表達(dá)式的結(jié)果是逗號右邊表達(dá)式的值。如果你寫一個非成員函數(shù)operator,你不能保證左邊的表達(dá)式先于右邊的表達(dá)式計(jì)算,因?yàn)楹瘮?shù)(operator)調(diào)用時兩個表達(dá)式作為參數(shù)被傳遞出去。但是你不能控制函數(shù)參數(shù)的計(jì)算順序。所以非成員函數(shù)的方法絕對不行。成員函數(shù)operator,你也不能依靠于逗號左邊表達(dá)式先被計(jì)算的行為特性,因?yàn)榫幾g器不一定必須按此方法去計(jì)算。因此你不能重載逗號操作符,保證它的行為特性與其被料想的一樣。重載它是完全輕率的行為。

          8. 理解各種不同含義的new和delete

          class Widget8 {
          public:
          Widget8(int widget8Size) {}
          };

          void* mallocShared(size_t size)
          {
          return operator new(size);
          }

          voidfreeShared(void* memory)
          {
          operatordelete(memory);
          }

          Widget8* constructWidget8InBuffer(void* buffer, int widget8Size)
          {
          return new(buffer) Widget8(widget8Size); // new操作符的一個用法,需要使用一個額外的變量(buffer),當(dāng)new操作符隱含調(diào)用operator new函數(shù)時,把這個變量傳遞給它
          // 被調(diào)用的operator new函數(shù)除了待有強(qiáng)制的參數(shù)size_t外,還必須接受void*指針參數(shù),指向構(gòu)造對象占用的內(nèi)存空間。這個operator new就是placement new,它看上去像這樣:
          // void * operator new(size_t, void* location) { return location; }
          }

          inttest_item_8
          {
          std::string* ps = new std::string("Memory Management"); // 使用的new是new操作符(new operator)
          //void * operator new(size_t size); // 函數(shù)operator new通常聲明
          void* rawMemory = operator new(sizeof(std::string)); // 操作符operator new將返回一個指針,指向一塊足夠容納一個string類型對象的內(nèi)存
          operatordelete(rawMemory);

          delete ps; // ps->~std::string; operator delete(ps);

          void* buffer = operator new(50*sizeof(char)); // 分配足夠的內(nèi)存以容納50個char,沒有調(diào)用構(gòu)造函數(shù)
          operatordelete(buffer); // 釋放內(nèi)存,沒有調(diào)用析構(gòu)函數(shù). 這與在C中調(diào)用malloc和free等同OA

          void* sharedMemory = mallocShared(sizeof(Widget8));
          Widget8* pw = constructWidget8InBuffer(sharedMemory, 10); // placement new
          //delete pw; // 結(jié)果不確定,共享內(nèi)存來自mallocShared,而不是operator new
          pw->~Widget8; // 正確,析構(gòu)pw指向的Widget8,但是沒有釋放包含Widget8的內(nèi)存
          freeShared(pw); // 正確,釋放pw指向的共享內(nèi)存,但是沒有調(diào)用析構(gòu)函數(shù)

          return 0;
          }

          new操作符(new operator)和new操作(operator new)的區(qū)別:

          new操作符就像sizeof一樣是語言內(nèi)置的,你不能改變它的含義,它的功能總是一樣的。它要完成的功能分成兩部分。第一部分是分配足夠的內(nèi)存以便容納所需類型的對象。第二部分是它調(diào)用構(gòu)造函數(shù)初始化內(nèi)存中的對象。new操作符總是做這兩件事情,你不能以任何方式改變它的行為。你所能改變的是如何為對象分配內(nèi)存。new操作符調(diào)用一個函數(shù)來完成必須的內(nèi)存分配,你能夠重寫或重載這個函數(shù)來改變它的行為。new操作符為分配內(nèi)存所調(diào)用函數(shù)的名字是operator new。

          函數(shù)operator new通常聲明:返回值類型是void*,因?yàn)檫@個函數(shù)返回一個未經(jīng)處理(raw)的指針,未初始化的內(nèi)存。參數(shù)size_t確定分配多少內(nèi)存。你能增加額外的參數(shù)重載函數(shù)operator new,但是第一個參數(shù)類型必須是size_t。就像malloc一樣,operator new的職責(zé)只是分配內(nèi)存。它對構(gòu)造函數(shù)一無所知。把operator new返回的未經(jīng)處理的指針傳遞給一個對象是new操作符的工作。

          placement new:特殊的operator new,接受的參數(shù)除了size_t外還有其它。

          new操作符(new operator)與operator new關(guān)系:你想在堆上建立一個對象,應(yīng)該用new操作符。它既分配內(nèi)存又為對象調(diào)用構(gòu)造函數(shù)。如果你僅僅想分配內(nèi)存,就應(yīng)該調(diào)用operator new函數(shù),它不會調(diào)用構(gòu)造函數(shù)。如果你想定制自己的在堆對象被建立時的內(nèi)存分配過程,你應(yīng)該寫你自己的operator new函數(shù),然后使用new操作符,new操作符會調(diào)用你定制的operator new。如果你想在一塊已經(jīng)獲得指針的內(nèi)存里建立一個對象,應(yīng)該用placement new。

          Deletion and Memory Deallocation:為了避免內(nèi)存泄漏,每個動態(tài)內(nèi)存分配必須與一個等同相反的deallocation對應(yīng)。函數(shù)operator delete與delete操作符的關(guān)系與operator new與new操作符的關(guān)系一樣。

          如果你用placement new在內(nèi)存中建立對象,你應(yīng)該避免在該內(nèi)存中用delete操作符。因?yàn)閐elete操作符調(diào)用operator delete來釋放內(nèi)存,但是包含對象的內(nèi)存最初不是被operator nen分配的,placement new只是返回轉(zhuǎn)到給它的指針。

          Arrays:operator new、operator delete

          9. 使用析構(gòu)函數(shù)防止資源泄漏

          用一個對象存儲需要被自動釋放的資源,然后依靠對象的析構(gòu)函數(shù)來釋放資源,這種思想不只是可以運(yùn)用在指針上,還能用在其它資源的分配和釋放上。

          資源應(yīng)該被封裝在一個對象里,遵循這個規(guī)則,你通常就能夠避免在存在異常環(huán)境里發(fā)生資源泄漏,通過智能指針的方式。

          C++確保刪除空指針是安全的,所以析構(gòu)函數(shù)在刪除指針前不需要檢測這些指針是否指向了某些對象。

          10. 在構(gòu)造函數(shù)中防止資源泄漏

          C++僅僅能刪除被完全構(gòu)造的對象(fully constructed objects),只有一個對象的構(gòu)造函數(shù)完全運(yùn)行完畢,這個對象才被完全地構(gòu)造。C++拒絕為沒有完成構(gòu)造操作的對象調(diào)用析構(gòu)函數(shù)。

          在構(gòu)造函數(shù)中可以使用try catch throw捕獲所有的異常。更好的解決方法是通過智能指針的方式。

          如果你用對應(yīng)的std::unique_ptr對象替代指針成員變量,就可以防止構(gòu)造函數(shù)在存在異常時發(fā)生資源泄漏,你也不用手工在析構(gòu)函數(shù)中釋放資源,并且你還能像以前使用非const指針一樣使用const指針,給其賦值。

          std::unique_ptr的使用參考:https://blog.csdn.net/fengbingchun/article/details/52203664

          11. 禁止異常信息(exceptions)傳遞到析構(gòu)函數(shù)外

          禁止異常傳遞到析構(gòu)函數(shù)外有兩個原因:第一能夠在異常傳遞的堆棧輾轉(zhuǎn)開解(stack-unwinding)的過程中,防止terminate被調(diào)用。第二它能幫助確保析構(gòu)函數(shù)總能完成我們希望它做的所有事情。

          12. 理解”拋出一個異常”與”傳遞一個參數(shù)”或”調(diào)用一個虛函數(shù)”間的差異

          你調(diào)用函數(shù)時,程序的控制權(quán)最終還會返回到函數(shù)的調(diào)用處,但是當(dāng)你拋出一個異常時,控制權(quán)永遠(yuǎn)不會回到拋出異常的地方。

          C++規(guī)范要求被作為異常拋出的對象必須被復(fù)制。即使被拋出的對象不會被釋放,也會進(jìn)行拷貝操作。拋出異常運(yùn)行速度比參數(shù)傳遞要慢。

          當(dāng)異常對象被拷貝時,拷貝操作是由對象的拷貝構(gòu)造函數(shù)完成的。該拷貝構(gòu)造函數(shù)是對象的靜態(tài)類型(static type)所對應(yīng)類的拷貝構(gòu)造函數(shù),而不是對象的動態(tài)類型(dynamic type)對應(yīng)類的拷貝構(gòu)造函數(shù)。

          catch子句中進(jìn)行異常匹配時可以進(jìn)行兩種類型轉(zhuǎn)換:第一種是繼承類與基類間的轉(zhuǎn)換。一個用來捕獲基類的catch子句也可以處理派生類類型的異常。這種派生類與基類(inheritance_based)間的異常類型轉(zhuǎn)換可以作用于數(shù)值、引用以及指針上。第二種是允許從一個類型化指針(typed pointer)轉(zhuǎn)變成無類型指針(untyped pointer),所以帶有const void*指針的catch子句能捕獲任何類型的指針類型異常。

          catch子句匹配順序總是取決于它們在程序中出現(xiàn)的順序。因此一個派生類異常可能被處理其基類異常的catch子句捕獲,即使同時存在有能直接處理該派生類異常的catch子句,與相同的try塊相對應(yīng)。不要把處理基類異常的catch子句放在處理派生類異常的catch子句的前面。

          把一個對象傳遞給函數(shù)或一個對象調(diào)用虛擬函數(shù)與把一個對象作為異常拋出,這之間有三個主要區(qū)別:第一,異常對象在傳遞時總被進(jìn)行拷貝;當(dāng)通過傳值方式捕獲時,異常對象被拷貝了兩次。對象作為參數(shù)傳遞給函數(shù)時不一定需要被拷貝。第二,對象作為異常被拋出與作為參數(shù)傳遞給函數(shù)相比,前者類型轉(zhuǎn)換比后者要少(前者只有兩種轉(zhuǎn)換形式)。最后一點(diǎn),catch子句進(jìn)行異常類型匹配的順序是它們在源代碼中出現(xiàn)的順序,第一個類型匹配成功的catch將被用來執(zhí)行。當(dāng)一個對象調(diào)用一個虛擬函數(shù)時,被選擇的函數(shù)位于與對象類型匹配最佳的類里,即使該類不是在源代碼的最前頭。

          try catch介紹參考:https://blog.csdn.net/fengbingchun/article/details/65939258

          13. 通過引用(reference)捕獲異常

          通過指針捕獲異常不符合C++語言本身的規(guī)范。四個標(biāo)準(zhǔn)的異常----bad_alloc(當(dāng)operator new不能分配足夠的內(nèi)存時被拋出);bad_cast(當(dāng)dynamic_cast針對一個引用(reference)操作失敗時被拋出);bad_typeid(當(dāng)dynamic_cast對空指針進(jìn)行操作時被拋出);bad_exception(用于unexpected異常)----都不是指向?qū)ο蟮闹羔槪阅惚仨毻ㄟ^值或引用來捕獲它們。

          std::exception的介紹參考:https://blog.csdn.net/fengbingchun/article/details/78303734

          14. 審慎使用異常規(guī)格(exception specifications)

          如果一個函數(shù)拋出一個不在異常規(guī)格范圍里的異常,系統(tǒng)在運(yùn)行時能夠檢測出這個錯誤,然后一個特殊函數(shù)std::unexpected將被自動地調(diào)用(This function is automatically called when a function throws an exception that is not listed in its dynamic-exception-specifier.)。std::unexpected缺省的行為是調(diào)用函數(shù)std::terminate,而std::terminate缺省的行為是調(diào)用函數(shù)abort。應(yīng)避免調(diào)用std::unexpected。

          避免在帶有類型參數(shù)的模板內(nèi)使用異常規(guī)格。

          C++允許你用其它不同的異常類型替換std::unexpected異常,通過std::set_unexpected。

          15. 了解異常處理的系統(tǒng)開銷

          采用不支持異常的方法編譯的程序一般比支持異常的程序運(yùn)行速度更快所占空間也更小。

          為了減少開銷,你應(yīng)該避免使用無用的try塊。如果使用try塊,代碼的尺寸將增加并且運(yùn)行速度也會減慢。

          16. 牢記80-20準(zhǔn)則(80-20 rule)

          80-20準(zhǔn)則說的是大約20%的代碼使用了80%的程序資源;大約20%的代碼耗用了大約80%的運(yùn)行時間;大約20%的代碼使用了80%的內(nèi)存;大約20%的代碼執(zhí)行80%的磁盤訪問;80%的維護(hù)投入于大約20%的代碼上。基本的觀點(diǎn):軟件整體的性能取決于代碼組成中的一小部分。

          17. 考慮使用lazy evaluation(懶惰計(jì)算法)

          在某些情況下要求軟件進(jìn)行原來可以避免的計(jì)算,這時lazy evaluation才是有用的。

          18. 分期攤還期望的計(jì)算

          over-eager evaluation(過度熱情計(jì)算法):在要求你做某些事情以前就完成它們。隱藏在over-eager evaluation后面的思想是如果你認(rèn)為一個計(jì)算需要頻繁進(jìn)行,你就可以設(shè)計(jì)一個數(shù)據(jù)結(jié)構(gòu)高效地處理這些計(jì)算需求,這樣可以降低每次計(jì)算需求時的開銷。

          當(dāng)你必須支持某些操作而不總需要其結(jié)果時,lazy evaluation是在這種時候使用的用以提高程序效率的技術(shù)。當(dāng)你必須支持某些操作而其結(jié)果幾乎總是被需要或不止一次地需要時,over-eager是在這種時候使用的用以提高程序效率的一種技術(shù)。

          19. 理解臨時對象的來源

          size_t countChar(const std::string& str, char ch)
          {
          // 建立一個string類型的臨時對象,通過以buffer做為參數(shù)調(diào)用string的構(gòu)造函數(shù)來初始化這個臨時對象,
          // countChar的參數(shù)str被綁定在這個臨時的string對象上,當(dāng)countChar返回時,臨時對象自動釋放

          // 將countChar(const std::string& str, char ch)修改為countChar(std::string& str, char ch)則會error
          return 1;
          }

          #define MAX_STRING_LEN 64

          inttest_item_19
          {
          char buffer[MAX_STRING_LEN];
          char c;

          std::cin >> c >> std::setw(MAX_STRING_LEN) >> buffer;
          std::cout<<"There are "<<countChar(buffer, c)<<" occurrences of the character "<<c<<" in "<<buffer<<std::endl;

          return 0;
          }

          在C++中真正的臨時對象是看不見的,它們不出現(xiàn)在你的源代碼中。建立一個沒有命名的非堆(non-heap)對象會產(chǎn)生臨時對象。這種未命名的對象通常在兩種條件下產(chǎn)生:為了使函數(shù)成功調(diào)用而進(jìn)行隱式類型轉(zhuǎn)換和函數(shù)返回對象時。

          僅當(dāng)通過傳值(by value)方式傳遞對象或傳遞常量引用(reference-to-const)參數(shù)時,才會發(fā)生這些類型轉(zhuǎn)換。當(dāng)傳遞一個非常量引用(reference-to-non-const)參數(shù)對象,就不會發(fā)生。

          C++語言禁止為非常量引用(reference-to-non-const)產(chǎn)生臨時對象。

          臨時對象是有開銷的,所以你應(yīng)該盡可能地去除它們。在任何時候只要見到常量引用(reference-to-const)參數(shù),就存在建立臨時對象而綁定在參數(shù)上的可能性。在任何時候只要見到函數(shù)返回對象,就會有一個臨時對象被建立(以后被釋放)。

          20. 協(xié)助完成返回值優(yōu)化

          class Rational20 {
          public:
          Rational20(int numerator = 0, int denominator = 1) {}

          intnumerator const { return 1; }
          intdenominator const { return 2; }
          };

          const Rational20 operator*(const Rational20& lhs, const Rational20& rhs)
          {
          // 以某種方法返回對象,能讓編譯器消除臨時對象的開銷:這種技巧是返回constructor argument而不是直接返回對象
          return Rational20(lhs.numerator * rhs.numerator, lhs.denominator * rhs.denominator);
          }

          inttest_item_20
          {
          Rational20 a = 10;
          Rational20 b(1, 2);
          Rational20 c = a * b;

          return 0;
          }

          一些函數(shù)(operator*也在其中)必須要返回對象。這就是它們的運(yùn)行方法。

          C++規(guī)則允許編譯器優(yōu)化不出現(xiàn)的臨時對象(temporary objects out of existence)。

          21. 通過重載避免隱式類型轉(zhuǎn)換

          class UPInt21 { // unlimited precision integers class
          public:
          UPInt21 {}
          UPInt21(int value) {}
          };

          const UPInt21 operator+(const UPInt21& lhs, const UPInt21& rhs) // add UPInt21+UPInt21
          {
          return UPInt21(1);
          }

          const UPInt21 operator+(const UPInt21& lhs, int rhs) // add UPInt21+int
          {
          return UPInt21(1);
          }

          const UPInt21 operator+(int lhs, const UPInt21& rhs) // add int+UPInt21
          {
          return UPInt21(1);
          }

          int test_item_21
          {
          UPInt21 upi1, upi2;
          UPInt21 upi3 = upi1 + upi2; // 正確,沒有由upi1或upi2生成臨時對象
          upi3 = upi1 + 10; // 正確,沒有由upi1或10生成臨時對象
          upi3 = 10 + upi2; // 正確,沒有由10或upi2生成臨時對象

          // 注意:注釋掉上面的operator+(UPInt21&, int)和operator+(int, UPInt21&)也正確,但是會通過臨時對象把10轉(zhuǎn)換為UPInt21

          return 0;
          }

          在C++中有一條規(guī)則是每一個重載的operator必須帶有一個用戶定義類型(user-defined type)的參數(shù)。

          利用重載避免臨時對象的方法不只是用在operator函數(shù)上。

          沒有必要實(shí)現(xiàn)大量的重載函數(shù),除非你有理由確信程序使用重載函數(shù)以后其整體效率會有顯著的提高。

          22. 考慮用運(yùn)算符的賦值形式(op=)取代其單獨(dú)形式(op)

          class Rational22 {
          public:
          Rational22(int numerator = 0, int denominator = 1) {}
          Rational22& operator+=(const Rational22& rhs) { return *this; }
          Rational22& operator-=(const Rational22& rhs) { return *this; }
          };

          // operator+根據(jù)operator+=實(shí)現(xiàn)
          const Rational22 operator+(const Rational22& lhs, const Rational22& rhs)
          {
          return Rational22(lhs) += rhs;
          }

          // operator-根據(jù)operator-=實(shí)現(xiàn)
          const Rational22 operator-(const Rational22& lhs, const Rational22& rhs)
          {
          return Rational22(lhs) -= rhs;
          }

          就C++來說,operator+、operator=和operator+=之間沒有任何關(guān)系,因此如果你想讓三個operator同時存在并具有你所期望的關(guān)系,就必須自己實(shí)現(xiàn)它們。同理,operator-, *, /, 等等也一樣。

          確保operator的賦值形式(assignment version)(例如operator+=)與一個operator的單獨(dú)形式(stand-alone)(例如operator+)之間存在正常的關(guān)系,一種好方法是后者(指operator+)根據(jù)前者(指operator+=)來實(shí)現(xiàn)。

          23. 考慮變更程序庫

          不同的程序庫在效率、可擴(kuò)展性、移植性、類型安全和其它一些領(lǐng)域上蘊(yùn)含著不同的設(shè)計(jì)理念,通過變換使用給予性能更多考慮的程序庫,你有時可以大幅度地提供軟件的效率。

          24. 理解虛擬函數(shù)、多繼承、虛基類和RTTI所需的代碼

          當(dāng)調(diào)用一個虛擬函數(shù)時,被執(zhí)行的代碼必須與調(diào)用函數(shù)的對象的動態(tài)類型相一致;指向?qū)ο蟮闹羔樆蛞玫念愋褪遣恢匾摹4蠖鄶?shù)編譯器是使用virtual table和virtual table pointers,通常被分別地稱為vtbl和vptr。

          一個vtbl通常是一個函數(shù)指針數(shù)組。(一些編譯器使用鏈表來代替數(shù)組,但是基本方法是一樣的)在程序中的每個類只要聲明了虛函數(shù)或繼承了虛函數(shù),它就有自己的vtbl,并且類中vtbl的項(xiàng)目是指向虛函數(shù)實(shí)現(xiàn)體的指針。

          你必須為每個包含虛函數(shù)的類的virtual table留出空間。類的vtbl的大小與類中聲明的虛函數(shù)的數(shù)量成正比(包括從基類繼承的虛函數(shù))。每個類應(yīng)該只有一個virtual table,所以virtual table所需的空間不會太大,但是如果你有大量的類或者在每個類中有大量的虛函數(shù),你會發(fā)現(xiàn)vtbl會占用大量的地址空間。

          一些原因?qū)е卢F(xiàn)在的編譯器一般總是忽略虛函數(shù)的inline指令。

          Virtual table只實(shí)現(xiàn)了虛擬函數(shù)的一半機(jī)制,如果只有這些是沒有用的。只有用某種方法指出每個對象對應(yīng)的vtbl時,它們才能使用。這是virtual table pointer的工作,它來建立這種聯(lián)系。每個聲明了虛函數(shù)的對象都帶著它,它是一個看不見的數(shù)據(jù)成員,指向?qū)?yīng)類的virtual table。這個看不見的數(shù)據(jù)成員也稱為vptr,被編譯器加在對象里,位置只有編譯器知道。

          關(guān)于虛函數(shù)表的介紹參考:https://blog.csdn.net/fengbingchun/article/details/79592347

          虛函數(shù)是不能內(nèi)聯(lián)的。這是因?yàn)椤眱?nèi)聯(lián)”是指”在編譯期間用被調(diào)用的函數(shù)體本身來代替函數(shù)調(diào)用的指令”,但是虛函數(shù)的”虛”是指”直到運(yùn)行時才能知道要調(diào)用的是哪一個函數(shù)”。

          RTTI(運(yùn)行時類型識別)能讓我們在運(yùn)行時找到對象和類的有關(guān)信息,所以肯定有某個地方存儲了這些信息讓我們查詢。這些信息被存儲在類型為type_info的對象里,你能通過使用typeid操作符訪問一個類的type_info對象。

          關(guān)于typeid的使用參考:https://blog.csdn.net/fengbingchun/article/details/51866559

          RTTI被設(shè)計(jì)為在類的vtbl基礎(chǔ)上實(shí)現(xiàn)。

          25. 將構(gòu)造函數(shù)和非成員函數(shù)虛擬化

          虛擬構(gòu)造函數(shù)是指能夠根據(jù)輸入給它的數(shù)據(jù)的不同而建立不同類型的對象。虛擬拷貝構(gòu)造函數(shù)能返回一個指針,指向調(diào)用該函數(shù)的對象的新拷貝。類的虛擬拷貝構(gòu)造函數(shù)只是調(diào)用它們真正的拷貝構(gòu)造函數(shù)。被派生類重定義的虛擬函數(shù)不用必須與基類的虛擬函數(shù)具有一樣的返回類型。如果函數(shù)的返回類型是一個指向基類的指針(或一個引用),那么派生類的函數(shù)可以返回一個指向基類的派生類的指針(或引用)。

          26. 限制某個類所能產(chǎn)生的對象數(shù)量

          阻止建立某個類的對象,最容易的方法就是把該類的構(gòu)造函數(shù)聲明在類的private域。

          27. 要求或禁止在堆中產(chǎn)生對象

          // 判斷一個對象是否在堆中, HeapTracked不能用于內(nèi)建類型,因?yàn)閮?nèi)建類型沒有this指針
          typedef const void* RawAddress;
          class HeapTracked { // 混合類,跟蹤
          public:
          class MissingAddress {}; // 從operator new返回的ptr異常類
          virtual ~HeapTracked = 0;
          static void* operator new(size_t size);
          static void operatordelete(void* ptr);
          boolisOnHeap const;

          private:
          static std::list<RawAddress> addresses;
          };

          std::list<RawAddress> HeapTracked::addresses;

          HeapTracked::~HeapTracked {}

          void* HeapTracked::operatornew(size_t size)
          {
          void* memPtr = ::operator new(size);
          addresses.push_front(memPtr);
          return memPtr;
          }

          void HeapTracked::operatordelete(void* ptr)
          {
          std::list<RawAddress>::iterator it = std::find(addresses.begin, addresses.end, ptr);
          if (it != addresses.end) {
          addresses.erase(it);
          ::operatordelete(ptr);
          } else {
          throw MissingAddress; // ptr就不是用operator new分配的,所以拋出一個異常
          }
          }

          bool HeapTracked::isOnHeap const
          {
          // 生成的指針將指向"原指針指向?qū)ο髢?nèi)存"的開始處
          // 如果HeapTracked::operator new為當(dāng)前對象分配內(nèi)存,這個指針就是HeapTracked::operator new返回的指針
          const void* rawAddress = dynamic_cast<const void*>(this);
          std::list<RawAddress>::iterator it = std::find(addresses.begin, addresses.end, rawAddress);
          return it != addresses.end;
          }

          class Asset : public HeapTracked {};

          // 禁止堆對象
          class UPNumber27 {
          private:
          static void* operator new(size_t size);
          static void operatordelete(void* ptr);
          };

          void* UPNumber27::operatornew(size_t size)
          {
          return ::operator new(size);
          }

          void UPNumber27::operatordelete(void* ptr)
          {
          ::operatordelete(ptr);
          }

          class Asset27 {
          public:
          Asset27(int initValue) {}

          private:
          UPNumber27 value;
          };

          inttest_item_27
          {
          UPNumber27 n1; // okay
          static UPNumber27 n2; // also okay
          //UPNumber27* p = new UPNumber27; // error, attempt to call private operator new

          // UPNumber27的operator new是private這一點(diǎn) 不會對包含UPNumber27成員對象的對象的分配產(chǎn)生任何影響
          Asset27* pa = new Asset27(100); // 正確,調(diào)用Asset::operator new或::operator new,不是UPNumber27::operator new

          return 0;
          }

          禁止堆對象:禁止用于調(diào)用new,利用new操作符總是調(diào)用operator new函數(shù)這點(diǎn)來達(dá)到目的,可以自己聲明這個函數(shù),而且你可以把它聲明為private。

          28. 靈巧(smart)指針

          // 大多數(shù)靈巧指針模板
          template<class T>
          class SmartPtr {
          public:
          SmartPtr(T* realPtr = 0); // 建立一個靈巧指針指向dumb pointer(內(nèi)建指針)所指的對象,未初始化的指針,缺省值為0
          SmartPtr(const SmartPtr& rhs); // 拷貝一個靈巧指針
          ~SmartPtr; // 釋放靈巧指針
          // make an assignment to a smart ptr
          SmartPtr& operator=(const SmartPtr& rhs);
          T* operator-> const; // dereference一個靈巧指針以訪問所指對象的成員
          T& operator* const; // dereference靈巧指針

          private:
          T* pointee; // 靈巧指針?biāo)傅膶ο?br>};

          靈巧指針是一種外觀和行為都被設(shè)計(jì)成與內(nèi)建指針相類似的對象,不過它能提供更多的功能。它們有許多應(yīng)用的領(lǐng)域,包括資源管理和重復(fù)代碼任務(wù)的自動化。

          在C++11中auto_ptr已經(jīng)被廢棄,用unique_ptr替代。

          std::unique_ptr的使用參考:https://blog.csdn.net/fengbingchun/article/details/52203664

          29. 引用計(jì)數(shù)

          class String {
          public:
          String(const char* initValue = "");
          String(const String& rhs);
          String& operator=(const String& rhs);
          const char& operator(int index) const; // for const String
          char& operator(int index); // for non-const String
          ~String;

          private:
          // StringValue的主要目的是提供一個空間將一個特別的值和共享此值的對象的數(shù)目聯(lián)系起來
          struct StringValue { // holds a reference count and a string value
          int refCount;
          char* data;
          bool shareable; // 標(biāo)志,以指出它是否為可共享的
          StringValue(const char* initValue);
          ~StringValue;
          };

          StringValue* value; // value of this String
          };

          String::String(const char* initValue) : value(new StringValue(initValue))
          {}

          String::String(const String& rhs)
          {
          if (rhs.value->shareable) {
          value = rhs.value;
          ++value->refCount;
          } else {
          value = new StringValue(rhs.value->data);
          }
          }

          String& String::operator=(const String& rhs)
          {
          if (value == rhs.value) { // do nothing if the values are already the same
          return *this;
          }

          if (value->shareable && --value->refCount == 0) { // destroy *this's value if no one else is using it
          delete value;
          }

          if (rhs.value->shareable) {
          value = rhs.value; // have *this share rhs's value
          ++value->refCount;
          } else {
          value = new StringValue(rhs.value->data);
          }

          return *this;
          }

          const char& String::operator(int index) const
          {
          return value->data[index];
          }

          char& String::operator(int index)
          {
          // if we're sharing a value with other String objects, break off a separate copy of the value fro ourselves
          if (value->refCount > 1) {
          --value->refCount; // decrement current value's refCount, becuase we won't be using that value any more
          value = new StringValue(value->data); // make a copy of the value for ourselves
          }

          value->shareable = false;
          // return a reference to a character inside our unshared StringValue object
          return value->data[index];
          }

          String::~String
          {
          if (--value->refCount == 0) {
          delete value;
          }
          }

          String::StringValue::StringValue(const char* initValue) : refCount(1), shareable(true)
          {
          data = new char[strlen(initValue) + 1];
          strcpy(data, initValue);
          }

          String::StringValue::~StringValue
          {
          delete data;
          }

          // 基類,任何需要引用計(jì)數(shù)的類都必須從它繼承
          class RCObject {
          public:
          voidaddReference { ++refCount; }
          voidremoveReference { if (--refCount == 0) delete this; } // 必須確保RCObject只能被構(gòu)建在堆中
          voidmarkUnshareable { shareable = false; }
          boolisShareable const { return shareable; }
          boolisShared const { return refCount > 1; }

          protected:
          RCObject : refCount(0), shareable(true) {}
          RCObject(const RCObject& rhs) : refCount(0), shareable(true) {}
          RCObject& operator=(const RCObject& rhs) { return *this; }
          virtual ~RCObject = 0;

          private:
          int refCount;
          bool shareable;

          };

          RCObject::~RCObject {} // virtual dtors must always be implemented, even if they are pure virtual and do nothing

          // template class for smart pointers-to-T objects. T must support the RCObject interface, typically by inheriting from RCObject
          template<class T>
          class RCPtr {
          public:
          RCPtr(T* realPtr = 0) : pointee(realPtr) { init; }
          RCPtr(const RCPtr& rhs) : pointee(rhs.pointee) { init; }
          ~RCPtr { if (pointee) pointee->removeReference; }

          RCPtr& operator=(const RCPtr& rhs)
          {
          if (pointee != rhs.pointee) { // skip assignments where the value doesn't change
          if (pointee)
          pointee->removeReference; // remove reference to current value

          pointee = rhs.pointee; // point to new value
          init; // if possible, share it else make own copy
          }

          return *this;
          }

          T* operator-> const { return pointee; }
          T& operator* const { return *pointee; }

          private:
          T* pointee; // dumb pointer this object is emulating

          voidinit // common initialization
          {
          if (pointee == 0) // if the dumb pointer is , so is the smart one
          return;

          if (pointee->isShareable == false) // if the value isn't shareable copy it
          pointee = new T(*pointee);

          pointee->addReference; // note that there is now a new reference to the value
          }
          };

          // 將StringValue修改為是從RCObject繼承
          // 將引用計(jì)數(shù)功能移入一個新類(RCObject),增加了靈巧指針(RCPtr)來自動處理引用計(jì)數(shù)
          class String2 {
          public:
          String2(const char* value = "") : value(new StringValue(value)) {}
          const char& operator(int index) const { return value->data[index]; } // for const String2

          char& operator(int index) // for non-const String2
          {
          if (value->isShared)
          value = new StringValue(value->data);
          value->markUnshareable;
          return value->data[index];
          }

          private:
          // StringValue的主要目的是提供一個空間將一個特別的值和共享此值的對象的數(shù)目聯(lián)系起來
          struct StringValue : public RCObject { // holds a reference count and a string value
          char* data;

          StringValue(const char* initValue) { init(initValue); }
          StringValue(const StringValue& rhs) { init(rhs.data); }

          voidinit(const char* initValue)
          {
          data = new char[strlen(initValue) + 1];
          strcpy(data, initValue);
          }

          ~StringValue { delete data; }
          };

          RCPtr<StringValue> value; // value of this String2

          };

          inttest_item_29
          {
          String s1("More Effective C++");
          String s2 = s1;
          s1 = s2;
          fprintf(stdout, "char: %c\n", s1[2]);
          String s3 = s1;
          s3[5] = 'x';

          return 0;
          }

          引用計(jì)數(shù)是這樣一個技巧,它允許多個有相同值的對象共享這個值的實(shí)現(xiàn)。這個技巧有兩個常用動機(jī)。第一個是簡化跟蹤堆中的對象的過程。一旦一個對象通過調(diào)用new被分配出來,最要緊的就是記錄誰擁有這個對象,因?yàn)槠渌姓?---并且只有其所有者----負(fù)責(zé)對這個對象調(diào)用delete。但是,所有權(quán)可以被從一個對象傳遞到另外一個對象(例如通過傳遞指針型參數(shù))。引用計(jì)數(shù)可以免除跟蹤對象所有權(quán)的擔(dān)子,因?yàn)楫?dāng)使用引用計(jì)數(shù)后,對象自己擁有自己。當(dāng)沒人再使用它時,它自己自動銷毀自己。因此,引用計(jì)數(shù)是個簡單的垃圾回收體系。第二個動機(jī)是由于一個簡單的常識。如果很多對象有相同的值,將這個值存儲多次是很無聊的。更好的辦法是讓所有的對象共享這個值的實(shí)現(xiàn)。這么做不但節(jié)省內(nèi)存,而且可以使得程序運(yùn)行更快,因?yàn)椴恍枰獦?gòu)造和析構(gòu)這個值的拷貝。

          引用計(jì)數(shù)介紹參考:https://blog.csdn.net/fengbingchun/article/details/85861776

          實(shí)現(xiàn)引用計(jì)數(shù)不是沒有代價(jià)的。每個被引用的值帶一個引用計(jì)數(shù),其大部分操作都需要以某種形式檢查或操作引用計(jì)數(shù)。對象的值需要更多的內(nèi)存,而我們在處理它們時需要執(zhí)行更多的代碼。引用計(jì)數(shù)是基于對象通常共享相同的值的假設(shè)的優(yōu)化技巧。如果假設(shè)不成立的話,引用計(jì)數(shù)將比通常的方法使用更多的內(nèi)存和執(zhí)行更多的代碼。另一方面,如果你的對象確實(shí)有具有相同值的趨勢,那么引用計(jì)數(shù)將同時節(jié)省時間和空間。

          30. 代理類

          template<class T>
          class Array2D { // 使用代理實(shí)現(xiàn)二維數(shù)組
          public:
          Array2D(int i, int j) : i(i), j(j)
          {
          data.reset(new T[i*j]);
          }

          class Array1D { // Array1D是一個代理類,它的實(shí)例扮演的是一個在概念上不存在的一維數(shù)組
          public:
          Array1D(T* data) : data(data) {}
          T& operator(int index) { return data[index]; }
          const T& operator(int index) const { return data[index]; }

          private:
          T* data;
          };

          Array1D operator(int index) { return Array1D(data.get+j*index); }
          const Array1D operator(int index) const { return Array1D(data.get+j*index); }

          private:
          std::unique_ptr<T> data;
          int i, j;
          };

          // 可以通過代理類幫助區(qū)分通過operator進(jìn)行的是讀操作還是寫操作
          class String30 {
          public:
          String30(const char* value = "") : value(new StringValue(value)) {}

          class CharProxy { // proxies for string chars
          public:
          CharProxy(String30& str, int index) : theString(str), charIndex(index) {}

          CharProxy& operator=(const CharProxy& rhs)
          {
          // if the string is haring a value with other String objects,
          // break off a separate copy of the value for this string only
          if (theString.value->isShared)
          theString.value = new StringValue(theString.value->data);

          // now make the assignment: assign the value of the char
          // represented by rhs to the char represented by *this
          theString.value->data[charIndex] = rhs.theString.value->data[rhs.charIndex];
          return *this;
          }

          CharProxy& operator=(char c)
          {
          if (theString.value->isShared)
          theString.value = new StringValue(theString.value->data);
          theString.value->data[charIndex] = c;
          return *this;
          }

          operator char const { return theString.value->data[charIndex]; }

          private:
          String30& theString;
          int charIndex;
          };

          const CharProxy operator(int index) const // for const String30
          {
          return CharProxy(const_cast<String30&>(*this), index);
          }

          CharProxy operator(int index) // for non-const String30
          {
          return CharProxy(*this, index);
          }

          //friend class CharProxy;
          private:
          // StringValue的主要目的是提供一個空間將一個特別的值和共享此值的對象的數(shù)目聯(lián)系起來
          struct StringValue : public RCObject { // holds a reference count and a string value
          char* data;

          StringValue(const char* initValue) { init(initValue); }
          StringValue(const StringValue& rhs) { init(rhs.data); }

          void init(const char* initValue)
          {
          data = new char[strlen(initValue) + 1];
          strcpy(data, initValue);
          }

          ~StringValue { delete data; }
          };

          RCPtr<StringValue> value; // value of this String30

          };

          int test_item_30
          {
          Array2D<float> data(10, 20);
          fprintf(stdout, "%f\n", data[3][6]);

          String30 s1("Effective C++"), s2("More Effective C++"); // reference-counted strings using proxies
          fprintf(stdout, "%c\n", s1[5]); // still legal, still works
          s2[5] = 'x'; // also legal, also works
          s1[3] = s2[8]; // of course it's legal, of course it works

          //char* p = &s1[1]; // error, 通常,取proxy對象地址的操作與取實(shí)際對象地址的操作得到的指針,其類型是不同的,重載CharProxy類的取地址運(yùn)算可消除這個不同

          return 0;
          }

          可以通過代理類實(shí)現(xiàn)二維數(shù)組。

          可以通過代理類幫助區(qū)分通過operator進(jìn)行的是讀操作還是寫操作。

          Proxy類可以完成一些其它方法很難甚至可不能實(shí)現(xiàn)的行為。多維數(shù)組是一個例子,左值/右值的區(qū)分是第二個,限制隱式類型轉(zhuǎn)換是第三個。

          同時,proxy類也有缺點(diǎn)。作為函數(shù)返回值,proxy對象是臨時對象,它們必須被構(gòu)造和析構(gòu)。Proxy對象的存在增加了軟件的復(fù)雜度。從一個處理實(shí)際對象的類改換到處理proxy對象的類經(jīng)常改變了類的語義,因?yàn)閜roxy對象通常表現(xiàn)出的行為與實(shí)際對象有些微妙的區(qū)別。

          31. 讓函數(shù)根據(jù)一個以上的對象來決定怎么虛擬

          32. 在未來時態(tài)下開發(fā)程序

          未來時態(tài)的考慮增加了你的代碼的可重用性、可維護(hù)性、健壯性,以及在環(huán)境發(fā)生改變時易于修改。

          33. 將非尾端類設(shè)計(jì)為抽象類

          34. 如何在同一程序中混合使用C++和C

          名變換:就是C++編譯器給程序的每個函數(shù)換一個獨(dú)一無二的名字。在C中,這個過程是不需要的,因?yàn)闆]有函數(shù)重載,但幾乎所有C++程序都有函數(shù)重名。要禁止名變換,使用C++的extern “C”。不要將extern “C”看作是聲明這個函數(shù)是用C語言寫的,應(yīng)該看作是聲明這個函數(shù)應(yīng)該被當(dāng)作好像C寫的一樣而進(jìn)行調(diào)用。

          靜態(tài)初始化:在main執(zhí)行前和執(zhí)行后都有大量代碼被執(zhí)行。尤其是,靜態(tài)的類對象和定義在全局的、命名空間中的或文件體中的類對象的構(gòu)造函數(shù)通常在main被執(zhí)行前就被調(diào)用。這個過程稱為靜態(tài)初始化。同樣,通過靜態(tài)初始化產(chǎn)生的對象也要在靜態(tài)析構(gòu)過程中調(diào)用其析構(gòu)函數(shù),這個過程通常發(fā)生在main結(jié)束運(yùn)行之后。

          動態(tài)內(nèi)存分配:C++部分使用new和delete,C部分使用malloc(或其變形)和free。

          數(shù)據(jù)結(jié)構(gòu)的兼容性:在C++和C之間這樣相互傳遞數(shù)據(jù)結(jié)構(gòu)是安全的----在C++和C下提供同樣的定義來進(jìn)行編譯。在C++版本中增加非虛成員函數(shù)或許不影響兼容性,但幾乎其它的改變都將影響兼容。

          如果想在同一程序下混合C++與C編程,記住下面的指導(dǎo)原則:(1).確保C++和C編譯器產(chǎn)生兼容的obj文件;(2).將在兩種語言下都使用的函數(shù)聲明為extern “C”;(3).只要可能,用C++寫main;(4).總用delete釋放new分配的內(nèi)存;總用free釋放malloc分配的內(nèi)存;(5).將在兩種語言間傳遞的東西限制在用C編譯的數(shù)據(jù)結(jié)構(gòu)的范圍內(nèi);這些結(jié)構(gòu)的C++版本可以包含非虛成員函數(shù)。

          35. 讓自己習(xí)慣使用標(biāo)準(zhǔn)C++語言

          GitHub:https://github.com/fengbingchun/Messy_Test

          版權(quán)聲明:本文為CSDN博主「fengbingchun」的原創(chuàng)文章,版權(quán)歸作者所有。

          技術(shù)的道路一個人走著極為艱難?

          一身的本領(lǐng)得不施展?

          優(yōu)質(zhì)的文章得不到曝光?

          別擔(dān)心,

          即刻起,CSDN 將為你帶來創(chuàng)新創(chuàng)造創(chuàng)變展現(xiàn)的大舞臺,

          掃描下方二維碼,歡迎加入 CSDN 「原力計(jì)劃」!

          【End】

          he jean-der gap! Women's pockets are statistically PROVEN to be smaller than men's - with most unable to fit even an iPhone or a wallet

          女性朋友們總有這種苦惱,出門前想把手機(jī)和錢包放進(jìn)牛仔褲口袋,卻發(fā)現(xiàn)手機(jī)露了半個在外面,錢包也鼓出一截,只好再帶上個手袋放這些必需品。然而,男性的牛仔褲口袋卻可以輕松裝下。難道設(shè)計(jì)牛仔褲口袋也存在性別歧視嗎?

          The struggle is real for women when they want to carry items in their pockets without having to lug a handbag around.

          如果女性不想拿手袋,而是想把東西塞進(jìn)牛仔褲口袋里,真是有些麻煩。

          A study by The Puddingonly confirmed what most already know about jean pockets when it found women's were considerably smaller than ones created for men.

          《布丁》雜志開展的一項(xiàng)研究發(fā)現(xiàn),女性的牛仔褲口袋比男性的小很多。這也證實(shí)了人們之前關(guān)于牛仔褲口袋的普遍看法。

          In an analysis of 20 major jean brands, the group found on average women's jean front pockets are 48 percent shorter and 6.5 percent narrower than men's pockets.

          在一項(xiàng)針對20個知名牛仔褲品牌的分析中,研究小組發(fā)現(xiàn),與男性的口袋相比,女性牛仔褲前身口袋短了48%,窄了6.5%。

          People would think the purpose of a jean pocket would be so someone could carry necessary items in it — such as a phone, wallet or their own hand.

          But most women's front pockets prevent the wearer from placing most small-sized items in comfortably without them sticking out.

          人們會認(rèn)為設(shè)計(jì)牛仔褲口袋是為了隨身攜帶必需品,比如手機(jī)和錢包,或者只是為了把手插進(jìn)去。但大部分女性牛仔褲前身口袋小得讓大家無法舒服地裝進(jìn)最小號的物品,裝在口袋里的物品總有一部分露在外面。

          This was only confirmed by the study when it compared what could fit in the front pocket of women's jeans versus men's jeans.

          研究人員比較了男性和女性牛仔褲前身口袋的大小后,證實(shí)了這一點(diǎn)。

          When looking at what phone could fit into a woman's jean pocket, the study found only 40 percent of brands could hold an iPhoneX. Similarly only 20 percent could hold a Samsung Galaxy, and a shocking five percent could hold a Google Pixel.

          研究人員用不同型號的手機(jī)對女性牛仔褲口袋進(jìn)行測試,結(jié)果發(fā)現(xiàn),僅有40%的品牌牛仔褲口袋可以裝下一個iPhoneX手機(jī)。同樣地僅有20%的品牌牛仔褲口袋可以裝下一個三星Galaxy手機(jī),讓人吃驚的是,只有5%的品牌牛仔褲口袋可以裝下谷歌Pixel手機(jī)。

          These results largely differed from that of men's jean pockets.The study found 100 percent could hold an iPhoneX, 95 percent could hold a Samsung Galaxy and 85 percent could hold a Google Pixel.

          這些結(jié)果和男性牛仔褲口袋截然不同。研究發(fā)現(xiàn),口袋中能裝下上述三款手機(jī)的男性牛仔褲品牌分別占到100%、95%和85%。

          What was the most interesting comparison was to see which front pockets could fit a person's hand.

          最有趣的對比是看看哪些牛仔褲前身口袋可以塞進(jìn)一只手。

          Only 10 percent of the women's jean brands could fit a woman's hand and five percent could fit a male hand.

          只有10%的女性品牌牛仔褲口袋能放下女性的一只手,有5%能放下男性的一只手。

          In contrast, 100 percent of men's jean front pockets could fit a male or female hand.

          相比之下,全部的男性品牌牛仔褲口袋都能放下男性或女性的一只手。

          If someone is looking to buy jeans that will feature a larger front pocket for women, the study found they should turn to Abercrombie, American Eagle, and skinny H&M jeans.

          研究發(fā)現(xiàn),如果有人想購買大口袋的女性牛仔褲,可以選擇阿伯克龍比、美國鷹和緊身的H&M牛仔褲。

          After these results were revealed, some could argue that of course women's pockets would be smaller because they tend to be smaller than men.

          在這些研究結(jié)果發(fā)布后,一些人也許會說,女性的牛仔褲口袋當(dāng)然要小些,因?yàn)榕员緛砭捅饶行陨聿氖菪 ?/p>

          But the study made sure to look at all the brands with the same size jeans — a 32-inch waist — to show consistency in making the pockets smaller for someone arguably the same size just because of the gender differences.

          但研究人員選取的都是同樣腰圍(32英寸)的牛仔褲,在男性和女性身材相同的情況下,女性牛仔褲口袋還是會更小,僅僅是因?yàn)樾詣e不同。

          Now when the study looked at back pockets on jeans, it found there was only a slight difference between ones for women and ones for men.

          針對牛仔褲后身口袋的研究發(fā)現(xiàn),男性和女性牛仔褲的差異并不大。

          Women's back pockets were only five percent shorter and two percent narrower than that of men's.

          女性牛仔褲的后身口袋僅比男性口袋短5%,窄2%。

          The main purpose of this study, though, was to show how men are offered a larger area to store items in their pockets than women.

          這項(xiàng)研究主要為了揭示出男性牛仔褲的儲物空間比女性牛仔褲要大。

          It is not because they are larger — again the study compared jeans of the same sized waist — but because how the jean industry has decided to stick with a similar formula with pocket sizes for women.

          出現(xiàn)這種現(xiàn)象并不是因?yàn)槟行员扰愿吒郑ㄔ俅螐?qiáng)調(diào),研究人員調(diào)查的是相同腰圍尺寸的男女牛仔褲),而是因?yàn)榕W醒澬袠I(yè)堅(jiān)持采用女性口袋的尺寸標(biāo)準(zhǔn)。

          The fashion industry changes all the time (see the rise of the boyfriend jeans with larger pockets), so maybe it is time for the pocket sizes to alter for women with all types of pants.

          時尚產(chǎn)業(yè)一直在變化,比如男友牛仔褲(女性闊腿牛仔褲的一種,口袋較大)的興起,所以也許各種女性褲子的口袋大小都要改改了。

          英文來源:每日郵報(bào)

          翻譯&編輯:yaning

          文章來源:英語點(diǎn)津網(wǎng)


          主站蜘蛛池模板: 美日韩一区二区三区| 精品一区二区三区免费视频| 国产精品夜色一区二区三区| 亚洲AV无码第一区二区三区| 无码国产精成人午夜视频一区二区| 无码一区二区三区中文字幕| 四虎在线观看一区二区| 国产精品视频分类一区| 在线精品一区二区三区电影| 国产一区二区三区手机在线观看| 动漫精品一区二区三区3d | 成人在线一区二区| 精品无码人妻一区二区三区不卡| 天堂Aⅴ无码一区二区三区| 亚洲AV成人精品一区二区三区 | 日韩精品视频一区二区三区| 国产免费av一区二区三区| 人妻少妇AV无码一区二区| 免费无码A片一区二三区| 久久久久女教师免费一区| 国产对白精品刺激一区二区| 嫩B人妻精品一区二区三区| 中文字幕精品一区二区2021年| 国产AⅤ精品一区二区三区久久 | 无码一区二区三区爆白浆| 国产亚洲欧洲Aⅴ综合一区| 亚洲精品色播一区二区| 无码日韩精品一区二区三区免费| 韩国一区二区三区视频| 日韩一区二区在线观看视频| 相泽亚洲一区中文字幕| 天海翼一区二区三区高清视频| 一区二区三区国产精品 | 无码视频一区二区三区| 无码av免费一区二区三区试看| 中文字幕无线码一区| 久久久久人妻精品一区三寸蜜桃 | 中文字幕一区二区三 | 国产无吗一区二区三区在线欢| 无码国产精成人午夜视频一区二区| 久久一区二区免费播放|