練習(xí)一
以下函數(shù)完全沒有檢查可能的數(shù)據(jù)錯(cuò)誤以及可能的執(zhí)行失敗。請指出此函數(shù)中所有可能發(fā)生錯(cuò)誤的地方。本題并不考慮出現(xiàn)異常。
int *alloc_and_init(string file_name)
{
ifstream infile(file_name);
int elem_cnt;
infile >> elem_cnt;
int *pi = allocate_array(elem_cnt);
int elem;
int index = 0;
while(infile >> elem)
{
pi[index++] = elem;
}
sort_array(pi, elem_cnt);
register_data(pi);
return pi;
}
這是書中第203頁的練習(xí)7.1。
我自己的答案:打開文件后,未對infile進(jìn)行判斷,是否打開文件成功;pi是否分配成功,未進(jìn)行判斷,它是否為null。
侯捷老師給的答案如下:
第一個(gè)錯(cuò)誤便是“型別不符”。ifstream constructor 接受的參數(shù)型別是const char*而非string。這個(gè)沒有注意到。解決方法是利用string的c_str member function取得其c-style字符串表現(xiàn)形式:
ifstream infile(file_name.c_str());
第二個(gè)錯(cuò)誤是檢查infile是否成功開啟。
if ( !infile ) // 開啟失敗
第三個(gè)錯(cuò)誤就是infile >> elem_cnt 可能執(zhí)行失敗。
如,文件內(nèi)含的是文字,那么企圖“讀入某個(gè)數(shù)值并置于elem_cnt內(nèi)”的操作便告失敗。此外,文件也有可能是空的。必須檢查讀取是否成功。
infile >> elem_cnt;
if (! infile) // 讀取失敗
第四個(gè)錯(cuò)誤int *pi = allocate_array(elem_cnt);
無論何時(shí),當(dāng)我們處理指針時(shí),必須隨時(shí)注意指針是否的確指向?qū)嶋H存在的對象。如果allocate_array()無法配置足夠內(nèi)存,pi便會被設(shè)為0,我們必須檢驗(yàn)如下:
if ( ! pi ) // allocate_array() 沒有配置到內(nèi)存
需要說明的是:程序的假設(shè)是(1)elem_cnt代表文件中的元素個(gè)數(shù);(2)數(shù)組索引值index絕不會發(fā)生溢出。但是除非我們檢查,否則實(shí)在無法保證index永遠(yuǎn)不大于elem_cnt。
第一個(gè)錯(cuò)誤和第三個(gè)錯(cuò)誤,沒有考慮到。分析看,對于“型別不符”這個(gè)問題,一直沒有注意到。此外,對于讀入文字,沒有思考那么多。
努力學(xué)習(xí)ing……
posted @
2008-11-03 13:35 Sandy 閱讀(361) |
評論 (0) |
編輯 收藏
什么是內(nèi)存泄露
內(nèi)存泄露是一種實(shí)現(xiàn)錯(cuò)誤。它將會慢慢耗盡系統(tǒng)內(nèi)存空間。當(dāng)計(jì)算機(jī)運(yùn)行進(jìn)程的時(shí)候,可能需要或多或少的內(nèi)存。這主要以來于進(jìn)程每時(shí)每刻將要執(zhí)行的命令。當(dāng)進(jìn)程需要更多的內(nèi)存時(shí),將給操作系統(tǒng)提出請求。當(dāng)進(jìn)程不再需要內(nèi)存的時(shí)候,將會把內(nèi)存釋放掉,還給操作系統(tǒng)。這樣其他進(jìn)程才可以使用。如果進(jìn)程沒有正確的將內(nèi)存還給操作系統(tǒng),盡管它不再使用,但是內(nèi)存的狀態(tài)仍然是不可再分配。這將減少可用內(nèi)存。
一般我們常說的內(nèi)存泄露是指堆內(nèi)存的泄露。堆內(nèi)存是指程序從堆中分配的,大小任意的(內(nèi)存塊的大小可以在程序運(yùn)行期決定),使用完后必須釋放的內(nèi)存。應(yīng)用程序一般使用malloc,realloc,new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,程序必須負(fù)責(zé)相應(yīng)得調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能再次被使用,我們就說這塊內(nèi)存泄露了。
對于一些界面的資源,如window的創(chuàng)建,menu的創(chuàng)建,dc的創(chuàng)建等等,對于這些,我們需要在不使用它們的時(shí)候,調(diào)用相應(yīng)的函數(shù),進(jìn)行釋放。否則也將會造成內(nèi)存泄露。
內(nèi)存泄露的后果
內(nèi)存泄露會因?yàn)闇p少可用內(nèi)存的數(shù)量從而降低計(jì)算機(jī)的性能。最終,在最糟糕的情況下,過多的可用內(nèi)存被分配掉導(dǎo)致全部或部分設(shè)備停止正常工作,或者應(yīng)用程序崩潰。
內(nèi)存泄露可能不嚴(yán)重,甚至能夠被常規(guī)的手段檢測出來。在現(xiàn)代操作系統(tǒng)中,一個(gè)應(yīng)用程序使用的常規(guī)內(nèi)存在程序終止時(shí)被釋放。這表示一個(gè)短暫的應(yīng)用程序中的內(nèi)存泄露不會導(dǎo)致嚴(yán)重后果。
在以下情況下,內(nèi)存泄露導(dǎo)致較嚴(yán)重的后果:
一是程序運(yùn)行后置之不理,并且隨著時(shí)間的流失消耗越來越多的內(nèi)存(比如服務(wù)器上的后臺任務(wù),尤其是嵌入式系統(tǒng)中的后臺任務(wù),這些任務(wù)可能被運(yùn)行后很多年內(nèi)都置之不理);
二是新的內(nèi)存被頻繁的分配,比如當(dāng)現(xiàn)實(shí)電腦游戲或動畫視頻畫面時(shí);
三是程序能夠請求未被釋放的內(nèi)存(比如共享內(nèi)存),甚至是程序終止的時(shí)候;
四是泄露在操作系統(tǒng)內(nèi)部發(fā)生;
五是泄露在系統(tǒng)關(guān)鍵驅(qū)動中發(fā)生;
六是內(nèi)存非常有限,比如在嵌入式系統(tǒng)或便攜設(shè)備中
七是當(dāng)運(yùn)行于一個(gè)終止時(shí)內(nèi)存并不自動釋放的操作系統(tǒng)治上,而且一旦丟失,只能通過重啟來恢復(fù)。
在這里,我著重強(qiáng)調(diào)一下嵌入式系統(tǒng),由于系統(tǒng)內(nèi)存非常有限,編寫應(yīng)用程序的時(shí)候,一定要防止內(nèi)存泄露的發(fā)生。如果發(fā)生,可能是會使你編寫的應(yīng)用程序出現(xiàn)異常?;蛘吣愕南到y(tǒng)的性能將會大大降低。甚至有時(shí)你不得不依靠重起系統(tǒng)來恢復(fù)。
內(nèi)存泄露的檢測
檢測內(nèi)存泄露的工具:debugnew
http://dev.csdn.net/article/58/58407.shtm
淺談內(nèi)存泄漏(二)
http://www.vczx.com/article/show.php?id=68
一個(gè)跨平臺的 C++ 內(nèi)存泄漏檢測器
http://www-128.ibm.com/developerworks/cn/linux/l-mleak2/index.html
內(nèi)存泄露檢測
http://m.shnenglu.com/Ipedo/archive/2005/10/27/867.aspx
posted @
2008-11-02 10:50 Sandy 閱讀(377) |
評論 (0) |
編輯 收藏
提問的智慧 - How To Ask Questions The Smart Way
by Freesc Huang
http://fox23.cnblogs.com/
在各種技術(shù)社區(qū),論壇和郵件組,用戶和開發(fā)者們總是期望著自己能夠獲得幫助。在本文之前,曾經(jīng)有過一些經(jīng)典的文章,比如由Eric S. Raymond 和Rick Moen 撰寫的How to Ask Questions the Smart Way --- 我得承認(rèn)我盜用了這個(gè)文章的標(biāo)題:)
不過在我所關(guān)注的一些技術(shù)社區(qū)內(nèi),還是有一些朋友經(jīng)常華麗地忽視掉一些細(xì)節(jié),盡管某些問題實(shí)際上對提問者本身沒有什么關(guān)系,但是他們確實(shí)影響了看到這個(gè)問題的其他人的思路和感受。當(dāng)然,我必須得承認(rèn),當(dāng)寫下本文之前,曾經(jīng)我自己的某些提問可能也會有類似的問題:
注意社區(qū)板塊分類
在您發(fā)布一個(gè)主題的時(shí)候,請先確保您所發(fā)布的主題的確是和該板塊的定位相符的。一般的論壇板塊應(yīng)該都不是按板塊1,板塊2,板塊N來命名的,請您盡量先找到合適的板塊再提問。對于概要的問題不必放在細(xì)節(jié)的板塊中去討論,比如有關(guān).Net Framework運(yùn)行機(jī)制的討論就不益放在Visual C#的板塊中,而應(yīng)該去.Net Framework的板塊討論。
標(biāo)題格式
請您在標(biāo)題中盡量提供一些問題相關(guān)描述,比如你有疑問的控件名稱,出現(xiàn)的錯(cuò)誤信息,使用的開發(fā)語言,開發(fā)環(huán)境,目標(biāo)平臺和版本等。這樣既能方便回答問題的熱心人及時(shí)有效地回復(fù),又能方便以后的用戶來查找類似問題。盡量不要使用“跪求達(dá)人??!”,“我要瘋了??!”這類無意義的詞匯。
有關(guān)FAQ
基本所有技術(shù)社區(qū),特別是微軟的社區(qū),都會有提供FAQ之類的帖子或者公告,來幫助那些新手。先閱讀這些FAQ可以更快地認(rèn)識現(xiàn)狀和了解常見的問題,也許你的問題就在里面。FAQ是新人必看的資料。
使用搜索
請?jiān)谔釂柷俺浞质褂媚愕乃阉饕?,設(shè)想:如果你在某社區(qū)貼了一個(gè)問題,而當(dāng)你回頭在網(wǎng)上搜索的時(shí)候,立即發(fā)現(xiàn)一模一樣的問題居然有數(shù)萬條結(jié)果,你會覺得剛剛那個(gè)問題有些愚蠢。而更尷尬的是,你發(fā)現(xiàn)搜索結(jié)果的第一條居然就是前不久另一個(gè)同行發(fā)在同樣的社區(qū)的,而且已經(jīng)被解答了 = =!
心平氣和地提問
不需要使用“十萬火急!”,“在線急等!”這樣的字樣,每個(gè)人都很急切的希望知道問題的結(jié)果,但是不是每個(gè)人的問題都能及時(shí)被答復(fù),這很正常。也不要在你的帖子中破口大罵,即便您出現(xiàn)的問題的確很可惡。更不要隨意攻擊某產(chǎn)品和它們的開發(fā)人員,因?yàn)檫@對解決你的問題沒有任何幫助,沒有人愿意和一個(gè)咆哮的吵架者探討問題。
明確問題
一個(gè)明確的問題才有可能得到合適的回答,在您提問之前,您或許應(yīng)該先通過自己的嘗試盡量把您的問題明確化,具體化。否則很可能你在浪費(fèi)彼此的時(shí)間。
貼代碼是一種美德
誰都知道貼相關(guān)代碼是表達(dá)問題最直觀的方式,但是這個(gè)也是最容易被忽略的方式。很多開發(fā)者總是習(xí)慣一吐為快的感覺,說了很多話但是都沒有說到點(diǎn)子上,對企圖幫助你的人來說,你貼代碼顯然要比碼字更容易讓他們復(fù)現(xiàn)問題。
別忘了開發(fā)和運(yùn)行環(huán)境
你的程序是用什么開發(fā)的,VC6? VS2003/2005/2008?基于.Net Framework 2.0, 3.5?什么運(yùn)行環(huán)境?Windows XP?Windows Vista?Windows Mobile 6 Professional?
注意對問題現(xiàn)象的描述
這對你的提問很關(guān)鍵,我經(jīng)常看到有這樣的描述:“我試過了XXX函數(shù),但是不行!”,請問不行是什么意思?有異常么?具體的錯(cuò)誤信息是什么?還是根本沒有任何反應(yīng)?
不要多版面
把同樣的問題放在多個(gè)版面沒有任何意義,反而不方便提問者去查詢有用信息。放到一個(gè)“合適”的版面即可。
不要求人代工
不論有償還是無償,在版面上求人代工都是不妥的,技術(shù)社區(qū)是專門用作交流技術(shù)而不是專門用作外包的,而且你也無權(quán)利轉(zhuǎn)嫁老板給你的任何任務(wù)給其他人。
及時(shí)關(guān)閉已解決主題
如果你的問題已經(jīng)得到滿意的答案,請及時(shí)結(jié)貼,不要在同樣的主題貼下面引出多個(gè)問題,不斷提問。這樣既不利于你后面的問題被看到,也不利于其他用戶搜索問題。新的問題請開新的主題。
不要進(jìn)行郵件騷擾
如非特別說明,不要通過郵件回復(fù)給社區(qū)用戶,這不是他們來社區(qū)所希望的,在社區(qū)回帖或者在博客留言都是很好的方式,別人在有空的時(shí)候自然會看到你的問題。這也是對他人的尊重,通常大家只是希望在自己有空的時(shí)候去社區(qū)看看問題,誰也不希望在上班時(shí)郵箱被一堆來自持有各種心態(tài)的提問者的問題給暴掉。
表示感謝
別忘了對給予你幫助的人表示感謝,盡管這個(gè)對你的問題是否得到解答沒有任何影響,但這是禮貌,是對別人勞動的尊重。如果您是屬于提問之后不管的類型,有可能會讓人產(chǎn)生對您RPWT的疑問,也許那些對你有過幫助的人就不再愿意回答你的問題了。
更多…
如果您和我一樣對提問的技巧感興趣,推薦您閱讀以下文章:
How To Ask Questions The Smart Way
http://en.wikipedia.org/wiki/Wikipedia:Help_desk/How_to_ask
摘自:http://www.cnblogs.com/fox23/archive/2008/08/27/how-to-ask-questions-the-smart-way.html
posted @
2008-10-28 15:10 Sandy 閱讀(154) |
評論 (0) |
編輯 收藏
模式對話框和非模式對話框的區(qū)別
一、 創(chuàng)建的區(qū)別
在WIN32中,模式對話框的創(chuàng)建一般是使用DialogBox來進(jìn)行創(chuàng)建的。而非模式對話框則是利用CreateWindow來創(chuàng)建的。在MFC或是WTL中,模式對話框一般是使用DoModal,而非模式對話框的創(chuàng)建則是使用Create。
模式對話框創(chuàng)建后,程序的其他窗口便不能進(jìn)行操作,必須將該窗口關(guān)閉后,其他窗口才能進(jìn)行操作。而非模式對話框則無需這樣,它不強(qiáng)制要求用戶立即反應(yīng),而是與其他窗口同時(shí)接受用戶操作。
二、 消息響應(yīng)的區(qū)別
在消息響應(yīng)方面,模式對話框和非模式對話框之間又有著很大的區(qū)別。模式對話框工作的時(shí)候,它有內(nèi)部的消息泵機(jī)制,控件之間的交互不用我們?nèi)藶榈娜タ刂疲到y(tǒng)會幫助我們?nèi)ヌ幚怼7悄J綄υ捒騽t像普通窗口一樣,則由WinMain中書寫的消息循環(huán)驅(qū)動。但由于是對話框,它對一些消息有特殊的處理。因此,在消息循環(huán)中,需要先對對話框提供截獲消息的機(jī)會。
While (GetMessage(&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage(hDlgModeless, &msg))
{
TranslateMessage(&msg);
DispatchMessage( &msg);
}
}
如果當(dāng)前取得的消息是對話框的消息,IsDialogMessage 將它交由對話消息處理函數(shù)處理,并返回TRUE。不需要再派發(fā)了。
注意:這個(gè)方法并不是很好用,因?yàn)楫?dāng)對話框過多的時(shí)候,處理起來就比較麻煩了。另一種處理的方法是利用子類化控件的方法,來處理控件間的交互。
三、 銷毀的區(qū)別
模式對話框的銷毀是使用EndDialog,而非模式對話框的銷毀是使用DestroyWindow.。所以我們在銷毀對話框的時(shí)候,也要對其進(jìn)行區(qū)別。
非模式對話框,用戶關(guān)閉對話框時(shí),對話框消息處理函數(shù)將收到WM_CLOSE消息,接到后調(diào)用DestroyWindow以銷毀非模式對話框。
模式對話框,則一般響應(yīng)IDOK和IDCANCEL。在PPC上,我們對于OK鍵和X鍵的處理要注意這點(diǎn)。
四、 其他
非模態(tài)對話框的模板必須具有Visible風(fēng)格,否則對話框?qū)⒉豢梢?,而模態(tài)對話框則無需設(shè)置該項(xiàng)風(fēng)格。更保險(xiǎn)的辦法是調(diào)用ShowWindow(hDialog, SW_SHOW)來顯示對話框,而不管對話框是否具有Visible風(fēng)格?!?/span>
非模態(tài)對話框?qū)ο笫怯?/span>new操作符在堆中動態(tài)創(chuàng)建的,而不是以成員變量的形式嵌入到別的對象中或以局部變量的形式構(gòu)建在堆棧上。通常應(yīng)在對話框的擁有者窗口類內(nèi)聲明一個(gè)指向?qū)υ捒蝾惖闹羔槼蓡T變量,通過該指針可訪問對話框?qū)ο蟆?/span>
通過調(diào)用Create函數(shù)來啟動對話框,而不是DoModal,這是模態(tài)對話框的關(guān)鍵所在。由于Create函數(shù)不會啟動新的消息循環(huán),對話框與應(yīng)用程序共用同一個(gè)消息循環(huán),這樣對話框就不會壟斷用戶的輸入。Create在顯示了對話框后就立即返回,而DoModal是在對話框被關(guān)閉后才返回的。眾所周知,在MFC程序中,窗口對象的生存期應(yīng)長于對應(yīng)的窗口,也就是說,不能在未關(guān)閉屏幕上窗口的情況下先把對應(yīng)的窗口對象刪除掉。由于在Create返回后,不能確定對話框是否已關(guān)閉,這樣也就無法確定對話框?qū)ο蟮纳嫫?,因此只好在堆中?gòu)建對話框?qū)ο?,而不能以局部變量的形式來?gòu)建之。
因?yàn)槭怯?/span>new操作符構(gòu)建非模態(tài)對話框?qū)ο螅虼吮仨氃趯υ捒蜿P(guān)閉后,用delete操作符刪除對話框?qū)ο蟆?/span>
必須有一個(gè)標(biāo)志表明非模態(tài)對話框是否是打開的。這樣做的原因是用戶有可能在打開一個(gè)模態(tài)對話框的情況下,又一次選擇打開命令。程序根據(jù)標(biāo)志來決定是打開一個(gè)新的對話框,還是僅僅把原來打開的對話框激活。通常可以用擁有者窗口中的指向?qū)υ捒驅(qū)ο蟮闹羔樧鳛檫@種標(biāo)志,當(dāng)對話框關(guān)閉時(shí),給該指針賦NULL值,以表明對話框?qū)ο笠巡淮嬖诹恕?/span>
注意:在C++編程中,判斷一個(gè)位于堆中的對象是否存在的常用方法是判斷指向該對象的指針是否為空。這種機(jī)制要求程序員將指向該對象的指針初始化為NULL值,在創(chuàng)建對象時(shí)將返回的地址賦給該指針,而在刪除對象時(shí)將該指針置成NULL值?!?/span>
posted @
2008-10-26 21:47 Sandy 閱讀(1386) |
評論 (1) |
編輯 收藏
最近看書,看到了引用,對其用法不是很了解。從各處匯總了一些知識,如下:
什么是引用
引用是某一變量(目標(biāo))的一個(gè)別名,對引用的操作與對變量直接操作完全一樣。引用的聲明方法:類型標(biāo)識符 &引用名=目標(biāo)變量名;
【例1】:
int a
int &ra=a; //定義引用ra, 它是變量a的引用,即別名
對引用的幾點(diǎn)說明
(1)&在此不是求地址運(yùn)算,而是起標(biāo)識作用。
(2)類型標(biāo)識符是指目標(biāo)變量的類型。
(3)聲明引用時(shí),必須同時(shí)對其進(jìn)行初始化。
(4)引用聲明完畢后,相當(dāng)于目標(biāo)變量名有兩個(gè)名稱,即該目標(biāo)原名稱和引用名,且不能再把該引用名作為其他變量名的別名。
ra=1; 等價(jià)于 a=1;
(5)聲明一個(gè)引用,不是新定義了一個(gè)變量,它只表示該引用名是目標(biāo)變量名的一個(gè)別名,它本身不是一種數(shù)據(jù)類型,因此引用本身不占存儲單元,系統(tǒng)也不給引用分配存儲單元。故:對引用求地址,就是對目標(biāo)變量求地址。&ra與&a相等
(6)不能建立數(shù)組的引用。因?yàn)閿?shù)組是一個(gè)由若干個(gè)元素所組成的集合,所以無法建立一個(gè)數(shù)組的別名。
引用的用途
引用的主要用途是為了描述函數(shù)的參數(shù)和返回值,特別是為了運(yùn)算符的重載。
1、 引用作為參數(shù)
引用的一個(gè)重要作用就是作為函數(shù)的參數(shù)。以前的C語言中函數(shù)參數(shù)傳遞是值傳遞,如果有大塊數(shù)據(jù)作為參數(shù)傳遞的時(shí)候,采用的方案往往是指針,因?yàn)檫@樣可以避免將整塊數(shù)據(jù)全部壓棧,可以提高程序的效率。但是現(xiàn)在(C++中)又增加了一種同樣有效率的選擇(在某些特殊情況下又是必須的選擇),就是引用。
【例2】:
void swap(int &p1, int &p2) / /此處函數(shù)的形參p1, p2都是引用
{ int p; p=p1; p1=p2; p2=p; }
為在程序中調(diào)用該函數(shù),則相應(yīng)的主調(diào)函數(shù)的調(diào)用點(diǎn)處,直接以變量作為實(shí)參進(jìn)行調(diào)用即可,而不需要實(shí)參變量有任何的特殊要求。如:對應(yīng)上面定義的swap函數(shù),相應(yīng)的主調(diào)函數(shù)可寫為:
【例3】:
main( )
{
int a,b;
cin>>a>>b; // 輸入a,b兩變量的值
swap(a,b); //直接以變量a和b作為實(shí)參調(diào)用swap函數(shù)
cout<<a<< ' ' <<b; //輸出結(jié)果
}
上述程序運(yùn)行時(shí),如果輸入數(shù)據(jù)10 20并回車后,則輸出結(jié)果為20 10。
由【例2】可看出:
(1)傳遞引用給函數(shù)與傳遞指針的效果是一樣的。這時(shí),被調(diào)函數(shù)的形參就成為原來主調(diào)函數(shù)中的實(shí)參變量或?qū)ο蟮囊粋€(gè)別名來使用,所以在被調(diào)函數(shù)中對形參變量的操作就是對其相應(yīng)的目標(biāo)對象(在主調(diào)函數(shù)中)的操作。
(2)使用引用傳遞函數(shù)的參數(shù),在內(nèi)存中并沒有產(chǎn)生實(shí)參的副本,它是直接對實(shí)參操作;而使用一般變量傳遞函數(shù)的參數(shù),當(dāng)發(fā)生函數(shù)調(diào)用時(shí),需要給形參分配存儲單元,形參變量是實(shí)參變量的副本;如果傳遞的是對象,還將調(diào)用拷貝構(gòu)造函數(shù)。因此,當(dāng)參數(shù)傳遞的數(shù)據(jù)較大時(shí),用引用比用一般變量傳遞參數(shù)的效率和所占空間都好。
(3)使用指針作為函數(shù)的參數(shù)雖然也能達(dá)到與使用引用的效果,但是,在被調(diào)函數(shù)中同樣要給形參分配存儲單元,且需要重復(fù)使用"*指針變量名"的形式進(jìn)行運(yùn)算,這很容易產(chǎn)生錯(cuò)誤且程序的閱讀性較差;另一方面,在主調(diào)函數(shù)的調(diào)用點(diǎn)處,必須用變量的地址作為實(shí)參。而引用更容易使用,更清晰。
如果既要利用引用提高程序的效率,又要保護(hù)傳遞給函數(shù)的數(shù)據(jù)不在函數(shù)中被改變,就應(yīng)使用常引用。
2、 引用作為返回值
如果一個(gè)函數(shù)返回了引用,那么該函數(shù)的調(diào)用也可以被賦值。這里有一函數(shù),它擁有兩個(gè)引用參數(shù)并返回一個(gè)雙精度數(shù)的引用:
【例4】
double &max(double &d1,double &d2)
{
return d1>d2?d1:d2;
}
由于max()函數(shù)返回一個(gè)對雙精度數(shù)的引用,那么我們就可以用max() 來對其中較大的雙精度數(shù)加1:
max(x,y)+=1.0;
在Effecitve c++中指出,當(dāng)你必須返回一個(gè)對象時(shí)不要試圖返回一個(gè)引用。這又是為什么呢?我看了一下它的解釋
考慮一個(gè)代表有理數(shù)的類,包含一個(gè)將兩個(gè)有理數(shù)相乘的函數(shù):
class Rational {
public:
Rational(int numerator = 0, // see Item 24 for why this
int denominator = 1); // ctor isn't declared explicit
...
private:
int n, d; // numerator and denominator
friend const Rational // see Item 3 for why the
operator*(const Rational& lhs, // return type is cons
const Rational& rhs);
};
operator* 的這個(gè)版本以傳值方式返回它的結(jié)果,而且如果你沒有擔(dān)心那個(gè)對象的構(gòu)造和析構(gòu)的代價(jià),你就是在推卸你的專業(yè)職責(zé)。如果你不是迫不得已,你不應(yīng)該為這樣的一個(gè)對象付出成本。所以問題就在這里:你是迫不得已嗎?
哦,如果你能用返回一個(gè)引用來作為代替,你就不是迫不得已。但是,請記住一個(gè)引用僅僅是一個(gè)名字,一個(gè)實(shí)際存在的對象的名字。無論何時(shí)只要你看到一個(gè)引用的聲明,你應(yīng)該立刻問自己它是什么東西的另一個(gè)名字,因?yàn)樗囟ㄊ悄澄锏牧硪粋€(gè)名字。在這個(gè) operator* 的情況下,如果函數(shù)返回一個(gè)引用,它必須返回某個(gè)已存在的而且其中包含兩個(gè)對象相乘的產(chǎn)物的 Rational 對象的引用。
當(dāng)然沒有什么理由期望這樣一個(gè)對象在調(diào)用 operator* 之前就存在。也就是說,如果你有
Rational a(1, 2); // a = 1/2
Rational b(3, 5); // b = 3/5
Rational c = a * b; // c should be 3/10
似乎沒有理由期望那里碰巧已經(jīng)存在一個(gè)值為十分之三的有理數(shù)。不是這樣的,如果 operator* 返回這樣一個(gè)數(shù)的引用,它必須自己創(chuàng)建那個(gè)數(shù)字對象。
一個(gè)函數(shù)創(chuàng)建一個(gè)新對象僅有兩種方法:在棧上或者在堆上。棧上的生成物通過定義一個(gè)局部變量而生成。使用這個(gè)策略,你可以用這種方法試寫 operator*:
const Rational& operator*(const Rational& lhs, // warning! bad code!
const Rational& rhs)
{
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}
你可以立即否決這種方法,因?yàn)槟愕哪繕?biāo)是避免調(diào)用構(gòu)造函數(shù),而 result 正像任何其它對象一樣必須被構(gòu)造。一個(gè)更嚴(yán)重的問題是這個(gè)函數(shù)返回一個(gè)引向 result 的引用,但是 result 是一個(gè)局部對象,而局部對象在函數(shù)退出時(shí)被銷毀。那么,這個(gè) operator* 的版本不會返回引向一個(gè) Rational 的引用——它返回引向一個(gè)前 Rational;一個(gè)曾經(jīng)的 Rational;一個(gè)空洞的、惡臭的、腐敗的,從前是一個(gè) Rational 但永不再是的尸體的引用,因?yàn)樗呀?jīng)被銷毀了。任何調(diào)用者甚至于沒有來得及匆匆看一眼這個(gè)函數(shù)的返回值就立刻進(jìn)入了未定義行為的領(lǐng)地。這是事實(shí),任何返回一個(gè)引向局部變量的引用的函數(shù)都是錯(cuò)誤的。(對于任何返回一個(gè)指向局部變量的指針的函數(shù)同樣成立。)
那么,讓我們考慮一下在堆上構(gòu)造一個(gè)對象并返回引向它的引用的可能性?;诙训膶ο笸ㄟ^使用 new 而開始存在,所以你可以像這樣寫一個(gè)基于堆的 operator*:
const Rational& operator*(const Rational& lhs, // warning! more bad
const Rational& rhs) // code!
{
Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}
哦,你還是必須要付出一個(gè)構(gòu)造函數(shù)調(diào)用的成本,因?yàn)橥ㄟ^ new 分配的內(nèi)存要通過調(diào)用一個(gè)適當(dāng)?shù)臉?gòu)造函數(shù)進(jìn)行初始化,但是現(xiàn)在你有另一個(gè)問題:誰是刪除你用 new 做出來的對象的合適人選?
即使調(diào)用者盡職盡責(zé)且一心向善,它們也不太可能是用這樣的方案來合理地預(yù)防泄漏:
Rational w, x, y, z;
w = x * y * z;
這里,在同一個(gè)語句中有兩個(gè) operator* 的調(diào)用,因此 new 被使用了兩次,這兩次都需要使用 delete 來銷毀。但是 operator* 的客戶沒有合理的辦法進(jìn)行那些調(diào)用,因?yàn)樗麄儧]有合理的辦法取得隱藏在通過調(diào)用 operator* 返回的引用后面的指針。這是一個(gè)早已注定的資源泄漏。
似乎明白了一些:當(dāng)你必須返回一個(gè)對象時(shí)不要試圖返回一個(gè)引用。對于局部變量,返回其引用會造成錯(cuò)誤。為了避免錯(cuò)誤,我們應(yīng)盡量不返回引用。
3、 常引用
const引用是指向const對象的引用:
const int ival = 1024;
const int &refVal = ival; // ok: both reference and object are const
int &ref2 = ival; // error: non const reference to a const object
常引用聲明方式:const 類型標(biāo)識符 &引用名=目標(biāo)變量名;
用這種方式聲明的引用,不能通過引用對目標(biāo)變量的值進(jìn)行修改,從而使引用的目標(biāo)成為const,達(dá)到了引用的安全性。
【例5】:
int a ;
const int &ra = a;
ra=1; // 錯(cuò)誤
a=1; // 正確
這不光是讓代碼更健壯,也有些其它方面的需要。
【例6】:假設(shè)有如下函數(shù)聲明:
string foo( );
void bar(string & s);
那么下面的表達(dá)式將是非法的:
bar(foo( ))
bar("hello world");
原因在于foo( )和"hello world"串都會產(chǎn)生一個(gè)臨時(shí)對象,而在C++中,這些臨時(shí)對象都是const類型的。因此上面的表達(dá)式就是試圖將一個(gè)const類型的對象轉(zhuǎn)換為非const類型,這是非法的。
引用型參數(shù)應(yīng)該在能被定義為const的情況下,盡量定義為const 。
Const 引用與非const引用的區(qū)別
非const引用只能綁定到與該引用同類型的對象。
const引用則可以綁定到不同但相關(guān)的類型的對象或綁定到左值。
指針和引用的差別
1. 非空的差別任何情況下都不能使用指向空值的引用.一個(gè)引用必須總是指向某個(gè)對象. 不存在的指向空值的引用這個(gè)事實(shí)意味著使用引用的代碼效率比使用指針要高.
2. 合法性區(qū)別在使用引用之前不需要測試他的合法性.指針必須測試.
3. 可修改區(qū)別 指針可以被重新賦值給另一個(gè)不同的對象.但是引用總是指向在初始化的時(shí)候被制定的對象,以后不能改變.但是指定的對象其內(nèi)容可以改變. 應(yīng)該使用指針的情況: 可能存在不指向任何對象的可能性 需要在不同的時(shí)刻指向不同的對象(此時(shí),你能夠改變指針的指向) 應(yīng)該使用引用的情況: 如果總是指向一個(gè)對象并且一旦指向一個(gè)對象后就不會改變指向,使用此時(shí)應(yīng)使用引用。
要首先好好理解指針和引用的區(qū)別
指針與引用看上去完全不同(指針用操作符’*’和’->’,引用使用操作符’.’),但是它們似乎有相同的功能。指針與引用都是讓你間接引用其他對象。你如何決定在什么時(shí)候使用指針,在什么時(shí)候使用引用呢?
總的來說,在以下情況下你應(yīng)該使用指針,一是你考慮到存在不指向任何對象的可能(在這種情況下,你能夠設(shè)置指針為空),二是你需要能夠在不同的時(shí)刻指向不同的對象(在這種情況下,你能改變指針的指向)。如果總是指向一個(gè)對象并且一旦指向一個(gè)對象后就不會改變指向,那么你應(yīng)該使用引用。
還有一種情況,就是當(dāng)你重載某個(gè)操作符時(shí),你應(yīng)該使用引用。最普通的例子是操作符[]。這個(gè)操作符典型的用法是返回一個(gè)目標(biāo)對象,其能被賦值。
vector<int> v(10); //建立整形向量(vector),大小為10
//向量是一個(gè)在標(biāo)準(zhǔn)C庫中的一個(gè)模板 [Page]
v[5] = 10; // 這個(gè)被賦值的目標(biāo)對象就是操作符[]返回的值
如果操作符[]返回一個(gè)指針,那么后一個(gè)語句就得這樣寫:
*v[5] = 10;
但是這樣會使得v看上去象是一個(gè)向量指針。因此你會選擇讓操作符返回一個(gè)引用
當(dāng)你知道你必須指向一個(gè)對象并且不想改變其指向時(shí),或者在重載操作符并為防止不必要的語義誤解時(shí),你不應(yīng)該使用指針。而在除此之外的其他情況下,則應(yīng)使用指針 。
posted @
2008-10-12 21:18 Sandy 閱讀(256) |
評論 (0) |
編輯 收藏
今日從網(wǎng)上看到一篇好文章,匯總匯總,又拼湊拼湊,便有了下文。
static關(guān)鍵字是C、C++中都存在的關(guān)鍵字, 它主要有三種使用方式, 其中前兩種只指在C語言中使用, 第三種在C++中使用(C,C++中具體細(xì)微操作不盡相同, 本文以C++為準(zhǔn)).
(1) 局部靜態(tài)變量 靜態(tài)局部變量有兩個(gè)用法,記憶功能和全局生存期.
(2) 外部靜態(tài)變量/函數(shù) 用于全局變量,主要作用是限制此全局變量被其他的文件調(diào)用
(3) 靜態(tài)數(shù)據(jù)成員/成員函數(shù) 表示這個(gè)成員是屬于這個(gè)類但是不屬于類中任意特定對象
下面就這三種使用方式及注意事項(xiàng)分別說明
一、局部靜態(tài)變量
在C/C++中, 局部變量按照存儲形式可分為三種auto, static, register
與auto類型(普通)局部變量相比, static局部變量有三點(diǎn)不同
1. 存儲空間分配不同
auto類型分配在棧上, 屬于動態(tài)存儲類別, 占動態(tài)存儲區(qū)空間, 函數(shù)調(diào)用結(jié)束后自動釋放, 而static分配在靜態(tài)存儲區(qū), 在程序整個(gè)運(yùn)行期間都不釋放. 兩者之間的作用域相同, 但生存期不同.
2. static局部變量在所處模塊在初次運(yùn)行時(shí)進(jìn)行初始化工作, 且只操作一次
3. 對于局部靜態(tài)變量, 如果不賦初值, 編譯期會自動賦初值0或空字符, 而auto類型的初值是不確定的.(對于C++中的class對象例外, class的對象實(shí)例如果不初始化, 則會自動調(diào)用默認(rèn)構(gòu)造函數(shù), 不管是否是static類型)
特點(diǎn): static局部變量的”記憶性”與生存期的”全局性”
所謂“記憶性”是指在兩次函數(shù)調(diào)用時(shí), 在第二次調(diào)用進(jìn)入時(shí), 能保持第一次調(diào)用退出時(shí)的值.
示例程序一
#include <iostream>
using namespace std;
void staticLocalVar()
{
static int a = 0; // 運(yùn)行期時(shí)初始化一次,下次再調(diào)用時(shí),不進(jìn)行初始化工作
cout<<"a="<<a<<endl;
++a;
}
int main()
{
staticLocalVar(); // 第一次調(diào)用, 輸出a=0
staticLocalVar(); // 第二次調(diào)用, 記憶了第一次退出時(shí)的值, 輸出a=1
return 0;
}
應(yīng)用: 利用“記憶性”, 記錄函數(shù)調(diào)用的次數(shù)(示例程序一)
利用生存期的“全局性”,改善
“return a pointer / reference to a local object”的問題. Local object的問題在于退出函數(shù), 生存期即結(jié)束,利用static的作用, 延長變量的生存期.
示例程序二:
// IP address to string format
// Used in Ethernet Frame and IP Header analysis
const char * IpToStr(UINT32 IpAddr)
{
static char strBuff[16]; // static局部變量, 用于返回地址有效
const unsigned char *pChIP = (const unsigned char *)&IpAddr;
sprintf(strBuff, "%u.%u.%u.%u", pChIP[0], pChIP[1], pChIP[2], pChIP[3]);
return strBuff;
}
注意事項(xiàng):
1. “記憶性”, 程序運(yùn)行很重要的一點(diǎn)就是可重復(fù)性, 而static變量的“記憶性”破壞了這種可重復(fù)性, 造成不同時(shí)刻至運(yùn)行的結(jié)果可能不同.
2. “生存期”全局性和唯一性. 普通的local變量的存儲空間分配在stack上, 因此每次調(diào)用函數(shù)時(shí), 分配的空間都可能不一樣, 而static具有全局唯一性的特點(diǎn), 每次調(diào)用時(shí), 都指向同一塊內(nèi)存, 這就造成一個(gè)很重要的問題 ---- 不可重入性!!!
這樣在多線程程序設(shè)計(jì)或遞歸程序設(shè)計(jì)中, 要特別注意這個(gè)問題.
下面針對示例程序二, 分析在多線程情況下的不安全性.(為方便描述, 標(biāo)上行號)
①const char * IpToStr(UINT32 IpAddr)
② {
③ static char strBuff[16]; // static局部變量, 用于返回地址有效
④ const unsigned char *pChIP = (const unsigned char *)&IpAddr;
⑤ sprintf(strBuff, "%u.%u.%u.%u", pChIP[0], pChIP[1], pChIP[2], pChIP[3]);
⑥ return strBuff;
⑦ }
假設(shè)現(xiàn)在有兩個(gè)線程A,B運(yùn)行期間都需要調(diào)用IpToStr()函數(shù), 將32位的IP地址轉(zhuǎn)換成點(diǎn)分10進(jìn)制的字符串形式.
現(xiàn)A先獲得執(zhí)行機(jī)會, 執(zhí)行IpToStr(), 傳入的參數(shù)是0x0B090A0A, 順序執(zhí)行完應(yīng)該返回的指針存儲區(qū)內(nèi)容是: “10.10.9.11”, 現(xiàn)執(zhí)行到⑥時(shí), 失去執(zhí)行權(quán), 調(diào)度到B線程執(zhí)行, B線程傳入的參數(shù)是0xA8A8A8C0,執(zhí)行至⑦, 靜態(tài)存儲區(qū)的內(nèi)容是192.168.168.168. 當(dāng)再調(diào)度到A執(zhí)行時(shí), 從⑥繼續(xù)執(zhí)行, 由于strBuff的全局唯一性, 內(nèi)容已經(jīng)被B線程沖掉, 此時(shí)返回的將是192.168.168.168字符串, 不再是10.10.9.11字符串.
補(bǔ)充:靜態(tài)局部變量屬于靜態(tài)存儲方式,它具有以下特點(diǎn):
(1)靜態(tài)局部變量在函數(shù)內(nèi)定義 它的生存期為整個(gè)源程序,但是其作用域仍與自動變量相同,只能在定義該變量的函數(shù)內(nèi)使用該變量。退出該函數(shù)后,盡管該變量還繼續(xù)存在,但不能使用它。
(2)允許對構(gòu)造類靜態(tài)局部量賦初值 例如數(shù)組,若未賦以初值,則由系統(tǒng)自動賦以0值。
(3)對基本類型的靜態(tài)局部變量若在說明時(shí)未賦以初值,則系統(tǒng)自動賦予0值。而對自動變量不賦初值,則其值是不定的。根據(jù)靜態(tài)局部變量的特點(diǎn), 可以看出它是一種生存期為整個(gè)源程序的量。雖然離開定義它的函數(shù)后不能使用,但如再次調(diào)用定義它的函數(shù)時(shí),它又可繼續(xù)使用, 而且保存了前次被調(diào)用后留下的值。因此,當(dāng)多次調(diào)用一個(gè)函數(shù)且要求在調(diào)用之間保留某些變量的值時(shí),可考慮采用靜態(tài)局部變量。雖然用全局變量也可以達(dá)到上述目的,但全局變量有時(shí)會造成意外的副作用,因此仍以采用局部靜態(tài)變量為宜
二、外部靜態(tài)變量/函數(shù)
在C中static有了第二種含義:用來表示不能被其它文件訪問的全局變量和函數(shù)。 但為了限制全局變量/函數(shù)的作用域, 函數(shù)或變量前加static使得函數(shù)成為靜態(tài)函數(shù)。但此處“static”的含義不是指存儲方式,而是指對函數(shù)的作用域僅局限于本文件(所以又稱內(nèi)部函數(shù))。注意此時(shí), 對于外部(全局)變量, 不論是否有static限制, 它的存儲區(qū)域都是在靜態(tài)存儲區(qū), 生存期都是全局的. 此時(shí)的static只是起作用域限制作用, 限定作用域在本模塊(文件)內(nèi)部.
使用內(nèi)部函數(shù)的好處是:不同的人編寫不同的函數(shù)時(shí),不用擔(dān)心自己定義的函數(shù),是否會與其它文件中的函數(shù)同名。
示例程序三:
//file1.cpp
static int varA;
int varB;
extern void funA()
{
……
}
static void funB()
{
……
}
//file2.cpp
extern int varB; // 使用file1.cpp中定義的全局變量
extern int varA; // 錯(cuò)誤! varA是static類型, 無法在其他文件中使用
extern vod funA(); // 使用file1.cpp中定義的函數(shù)
extern void funB(); // 錯(cuò)誤! 無法使用file1.cpp文件中static函數(shù)
補(bǔ)充:全局變量(外部變量)的說明之前再冠以static 就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲方式, 靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲方式。 這兩者在存儲方式上并無不同。這兩者的區(qū)別雖在于非靜態(tài)全局變量的作用域是整個(gè)源程序,當(dāng)一個(gè)源程序由多個(gè)源文件組成時(shí),非靜態(tài)的全局變量在各個(gè)源文件中都是有效的。 而靜態(tài)全局變量則限制了其作用域, 即只在定義該變量的源文件內(nèi)有效, 在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個(gè)源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其它源文件中引起錯(cuò)誤。從以上分析可以看出, 把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域,限制了它的使用范圍。因此static 這個(gè)說明符在不同的地方所起的作用是不同的。
三、靜態(tài)數(shù)據(jù)成員/成員函數(shù)(C++特有)
C++重用了這個(gè)關(guān)鍵字,并賦予它與前面不同的第三種含義:表示屬于一個(gè)類而不是屬于此類的任何特定對象的變量和函數(shù). 這是與普通成員函數(shù)的最大區(qū)別, 也是其應(yīng)用所在, 比如在對某一個(gè)類的對象進(jìn)行計(jì)數(shù)時(shí),計(jì)數(shù)生成多少個(gè)類的實(shí)例, 就可以用到靜態(tài)數(shù)據(jù)成員. 在這里面, static既不是限定作用域的, 也不是擴(kuò)展生存期的作用, 指示變量/函數(shù)在此類中的唯一性. 這也是“屬于一個(gè)類而不是屬于此類的任何特定對象的變量和函數(shù)”的含義. 因?yàn)樗菍φ麄€(gè)類來說是唯一的, 因此不可能屬于某一個(gè)實(shí)例對象的. (針對靜態(tài)數(shù)據(jù)成員而言, 成員函數(shù)不管是否是static,在內(nèi)存中只有一個(gè)副本.普通成員函數(shù)調(diào)用時(shí), 需要傳入this指針,static成員函數(shù)調(diào)用時(shí), 沒有this指針. )
請看示例程序四
class EnemyTarget {
public:
EnemyTarget() { ++numTargets; }
EnemyTarget(const EnemyTarget&) { ++numTargets; }
~EnemyTarget() { --numTargets; }
static size_t numberOfTargets() { return numTargets; }
bool destroy(); // returns success of attempt to destroy
// EnemyTarget object
private:
static size_t numTargets; // object counter
};
// class statics must be defined outside the class;
// initialization is to 0 by default
size_t EnemyTarget::numTargets;
在這個(gè)例子中, 靜態(tài)數(shù)據(jù)成員numTargets就是用來計(jì)數(shù)產(chǎn)生的對象個(gè)數(shù)的.
在《c++ 程序設(shè)計(jì)語言》中,是這樣運(yùn)用的:
Static靜態(tài)成員,它是類的一部分,但卻不是該類的各個(gè)對象的一部分。一個(gè)static成員只有唯一的一份副本,但不像常規(guī)的非static成員那樣在每個(gè)對象里各有一份副本。 與此類似,一個(gè)需要訪問類成員,然而卻并不需要針對特定對象去調(diào)用的函數(shù),也被稱為一個(gè)static成員函數(shù)。其好處在于消除了由于依賴全局量而引起的問題
Class Date
{
Int d, m, y;
Static Date default_date;
Public:
Date(int dd=0, int mm=0, int yy=0);
//……
Static void set_default(int, int, int);
};
靜態(tài)成員可以像任何其他成員一樣引用,此外,對于靜態(tài)成員的引用不必提到任何對象,相反,在這里應(yīng)該成員的名字加上作為限定詞的類的名字。
Void f()
{
Date::set_default(4, 5, 1945);
}
靜態(tài)成員(包括函數(shù)和數(shù)據(jù)成員)都必須在某個(gè)地方另行定義。如
Date Date:::default_date(16, 12, 1770);
Void Date::set_default(int d, int m, int y)
{
Date::default_date = Date(d, m, y);
}
補(bǔ)充:內(nèi)部函數(shù)和外部函數(shù)
當(dāng)一個(gè)源程序由多個(gè)源文件組成時(shí),C語言根據(jù)函數(shù)能否被其它源文件中的函數(shù)調(diào)用,將函數(shù)分為內(nèi)部函數(shù)和外部函數(shù)。
1 內(nèi)部函數(shù)(又稱靜態(tài)函數(shù))
如果在一個(gè)源文件中定義的函數(shù),只能被本文件中的函數(shù)調(diào)用,而不能被同一程序其它文件中的函數(shù)調(diào)用,這種函數(shù)稱為內(nèi)部函數(shù)。
定義一個(gè)內(nèi)部函數(shù),只需在函數(shù)類型前再加一個(gè)“static”關(guān)鍵字即可,如下所示:
static 函數(shù)類型 函數(shù)名(函數(shù)參數(shù)表)
{……}
關(guān)鍵字“static”,譯成中文就是“靜態(tài)的”,所以內(nèi)部函數(shù)又稱靜態(tài)函數(shù)。但此處“static”的含義不是指存儲方式,而是指對函數(shù)的作用域僅局限于本文件。
使用內(nèi)部函數(shù)的好處是:不同的人編寫不同的函數(shù)時(shí),不用擔(dān)心自己定義的函數(shù),是否會與其它文件中的函數(shù)同名,因?yàn)橥矝]有關(guān)系。
2 外部函數(shù)
外部函數(shù)的定義:在定義函數(shù)時(shí),如果沒有加關(guān)鍵字“static”,或冠以關(guān)鍵字“extern”,表示此函數(shù)是外部函數(shù):
[extern] 函數(shù)類型 函數(shù)名(函數(shù)參數(shù)表)
{……}
調(diào)用外部函數(shù)時(shí),需要對其進(jìn)行說明:
[extern] 函數(shù)類型 函數(shù)名(參數(shù)類型表)[,函數(shù)名2(參數(shù)類型表2)……];
posted @
2008-10-11 10:40 Sandy 閱讀(381) |
評論 (1) |
編輯 收藏
在windows mobile 上如何修改菜單上的文字呢?
我原先也只是看別人的代碼,然后copy過來自己用,有的時(shí)候弄不清楚所以然,就會出錯(cuò)。
通過下面的方法,我們可以修改菜單上的文字:
1
HMENU hMenu=NULL;
2
TBBUTTONINFO tbbi =
{0};
3
tbbi.cbSize = sizeof(tbbi);
4
tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX;
5
SendMessage(hMenuHWND, TB_GETBUTTONINFO, 1, (LPARAM)&tbbi); //修改菜單項(xiàng) 在左邊為0,在右邊為1
6
hMenu = (HMENU)tbbi.lParam;
7
8
InsertMenu(hMenu,beforeItem,MF_BYCOMMAND,afterItem,sText); //加入含有欲改寫文本的菜單項(xiàng)
9
DeleteMenu(hMenu,beforeItem,MF_BYCOMMAND); //刪除被改寫的菜單
通過上面的方法,我們就能修改菜單上的文字。
此外,學(xué)習(xí)一下TB_GETBUTTONINFO
消息:TB_GETBUTTONINFO
作用:This message retrieves the information for a button in a toolbar.
使用:
wParam = (WPARAM)(INT) iID; lParam = (LPARAM)(LPTBBUTTONINFO) lptbbi;
參數(shù)介紹:
iID Button identifier.
lptbbi Long pointer to a TBBUTTONINFO structure that receives the button information. The cbSize and dwMask members of this structure must be filled in prior to sending this message.
posted @
2008-07-30 18:41 Sandy 閱讀(908) |
評論 (0) |
編輯 收藏
如何獲得單個(gè)進(jìn)程所占內(nèi)存的大小,也許很簡單,通過GetProcessMemoryInfo可以輕松獲得,然而那是在PC上。但在windows mobile 上,這個(gè)函數(shù)不存在,它的實(shí)現(xiàn)機(jī)制我也不太清楚。所以如何獲得一個(gè)進(jìn)程的占用內(nèi)存大小,則需要另辟蹊徑。不過目前,我還沒有找到。
我現(xiàn)在的方法,如下:
1
DWORD GetUsedMemory(DWORD pID)
2

{
3
DWORD memUsage = 0;
4
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, pID);
5
if (INVALID_HANDLE_VALUE != hSnapShot)
6
{
7
HEAPLIST32 heapList;
8
heapList.dwSize = sizeof(HEAPLIST32);
9
BOOL bOk = Heap32ListFirst(hSnapShot, &heapList);
10
for (; bOk; bOk = Heap32ListNext(hSnapShot, &heapList))
11
{
12
HEAPENTRY32 he;
13
he.dwSize = sizeof(HEAPENTRY32);
14
BOOL fOK = Heap32First(hSnapShot, &he, pID, heapList.th32HeapID);
15
for(; fOK; fOK = Heap32Next(hSnapShot, &he))
16
{
17
memUsage += he.dwBlockSize;
18
}
19
}
20
21
22
23
// 關(guān)閉快照句柄
24
CloseToolhelp32Snapshot(hSnapShot);
25
}
26
27
return memUsage;
28
29
}
以上的這個(gè)方法與實(shí)際有出入。
有沒有更好的辦法呢?希望研究過的和正在研究的人,或者感興趣的人,能夠指點(diǎn)一二,讓我能夠走出困惑。
posted @
2008-07-29 16:21 Sandy 閱讀(1158) |
評論 (4) |
編輯 收藏
查了很多資料 ,都說對于多語言要這樣寫:
簡體中文:
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32
繁體中文
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHT)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
#pragma code_page(950)
#endif //_WIN32
英語
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
對于簡體中文和英語而言,似乎還能顯示正確,但對于繁體而言,代碼頁設(shè)置成950后,就會顯示出問題,很是疑惑。但只將代碼頁改回936,這個(gè)問題就消失了,想不通為什么?
希望能在知道的多一點(diǎn)。
posted @
2008-05-13 13:48 Sandy 閱讀(487) |
評論 (0) |
編輯 收藏