• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            2011年8月21日

            Basic Sample Senario :

            Client 需要一種組件提供一種 FastString類(lèi), 此類(lèi)具有 int length() 方法

            解決方案:

            靜態(tài)鏈接 : 組件廠商將源代碼交給 client ,客戶將組件代碼與client 代碼編譯連接運(yùn)行。 如果組件代碼需要fix bug or update ,則client 端代碼需要重新編譯連接。 而且client軟件的不同實(shí)例使用各自的組件內(nèi)存對(duì)象。

            動(dòng)態(tài)鏈接 : 組件廠商使用DLL形式發(fā)放組件,此時(shí)不同的client實(shí)例可以共享組件在內(nèi)存中的代碼段。

            DLL的問(wèn)題:1.導(dǎo)出名稱的問(wèn)題 : 不同的compiler可以使用不同的mangle name 用來(lái)區(qū)分 c++的函數(shù),那么使用不同的compiler的client和組件無(wú)法鏈接 (可以使用extern “C”解決全局函數(shù)名的問(wèn)題,使用 .DEF文件解決導(dǎo)出成員函數(shù)的問(wèn)題)

                               2.升級(jí)的問(wèn)題 :如果組件最初定義為

            class FastString
            {
                char* m_psz;
            public:
                FastString(const char* psz){strcpy(m_psz, psz);}
            };

                                                      而后廠商更改了組件的實(shí)現(xiàn)

            class FastString
            {
            int newmember;
            char* psz;
            public:

            FastString(const char* psz){strcpy(m_psz, psz);}

            }

            原來(lái)FastString對(duì)象大小為4字節(jié),現(xiàn)在變?yōu)?字節(jié),但是client端按照4字節(jié)分配對(duì)象, dll卻要向后面的4個(gè)字節(jié)存入一個(gè)指針,行為不可預(yù)料!

            解決這一問(wèn)題的一種方法便是每次發(fā)布便更改dll的名字,即1.0, 2.0, x.0 等等。但這樣比較弱啊!!

            這種問(wèn)題根本原因是啥呢?

            class 的關(guān)鍵在于封裝了其中的實(shí)現(xiàn)細(xì)節(jié),即用戶知道類(lèi)提供了哪些服務(wù)( public方法)就行了,不需要管類(lèi)的內(nèi)部到底使用了哪些成員變量。這樣一來(lái),只要接口沒(méi)變(類(lèi)提供功能),user就可以安心的使用任意版本的實(shí)現(xiàn)了。C++怎么不行呢?C++告訴用戶接口的同時(shí),也告訴了用戶類(lèi)的實(shí)現(xiàn)(對(duì)象布局)。比如類(lèi)對(duì)象有多大啊,每個(gè)成員的偏移啊(具體可以看Inside c++ object model)。知道了這些,客戶端使用接口的代碼就和DLL中的具體實(shí)現(xiàn)緊密的耦合起來(lái)了,杯具 啊~

            咋辦呢? 只要不讓client直接創(chuàng)建FastString就行了,這樣client的代碼就不會(huì)受到FastString實(shí)現(xiàn)變化的影響了。給FastString加一個(gè)Wrapper類(lèi),內(nèi)部嵌套一個(gè)FastString,所有對(duì)FastString的調(diào)用都foward給內(nèi)部的FastString member, 創(chuàng)建FastString 的任務(wù)在dll方面完成,client只知道Wrapper大小為4個(gè)字節(jié)--指向FastString的指針。這樣問(wèn)題解決了,但是太麻煩了,所有的接口都要包一層!! 而且多了一層調(diào)用!

            還有啥辦法么? 為了保證c++接口類(lèi)實(shí)現(xiàn)二進(jìn)制級(jí)別的兼容只能使用編譯器無(wú)關(guān)的特性:1.假設(shè)復(fù)合類(lèi)型表現(xiàn)形式相同(struct) 2. 傳參順序相同,可以使用指示符指定3.虛函數(shù)調(diào)用機(jī)制相同,即基于 vtbl 和 vptr. 基于這些假設(shè),我們創(chuàng)建的c++接口類(lèi)所有函數(shù)設(shè)置為虛函數(shù),那么不同compiler將為客戶端方法調(diào)用產(chǎn)生相同的機(jī)器代碼。定義了接口,便規(guī)定了所有繼承于他的類(lèi)的內(nèi)存結(jié)構(gòu)一定與它兼容。但此時(shí)不能告訴用戶類(lèi)的定義,否則重回上面的老路上了。怎么辦,只有接口客戶無(wú)法創(chuàng)建類(lèi)的定義,只有export一個(gè)創(chuàng)建類(lèi)對(duì)象的函數(shù)客戶了。  同上面的wrapper一樣,創(chuàng)建類(lèi)的操作僅僅在dll內(nèi)部調(diào)用,這意味著實(shí)際建造類(lèi)對(duì)象大小和布局的代碼與編譯實(shí)現(xiàn)類(lèi)的方法的代碼使用同樣的編譯器創(chuàng)建 (即ctor和call ctor的代碼由同一編譯器同時(shí)編譯)。由于虛析構(gòu)函數(shù)在vtbl的位置與compiler相關(guān),所以不能把它設(shè)置為虛函數(shù),只有顯示增加一個(gè)Delete函數(shù)完成析構(gòu)工作。

            OK,當(dāng)前我們得到的DLL中只有創(chuàng)建類(lèi)對(duì)象的函數(shù)需要用extern “C”export 給客戶,其他的接口中的虛函數(shù)是通過(guò)虛表訪問(wèn)的,無(wú)需靠符號(hào)名字鏈接。

            進(jìn)一步的,如果我們要給接口增加一個(gè)功能呢? 如果直接在現(xiàn)有接口中方法聲明后加入新的方法,那么此方法會(huì)出現(xiàn)在vtbl的最后一欄,舊的client不會(huì)調(diào)用新方法,但是如果新的client訪問(wèn)老的對(duì)象呢? 不幸的事情發(fā)生了! 這樣做的問(wèn)題在于,修改公開(kāi)的接口就打破了對(duì)象的封裝性。

            那么增加接口功能只能通過(guò)設(shè)計(jì)一個(gè)接口繼承另一個(gè)接口,或者讓類(lèi)繼承多個(gè)接口來(lái)實(shí)現(xiàn)了。客戶可以在運(yùn)行時(shí)通過(guò)RTTI來(lái)詢問(wèn)對(duì)象,支持這個(gè)功能不,親?然而 ,RTTI也是一個(gè)compiler相關(guān)的東東,好吧,我們讓每個(gè)類(lèi)自己實(shí)現(xiàn)RTTI,也就是實(shí)現(xiàn)一個(gè)dynamic_cast 方法, 用來(lái)將自己cast成為自己實(shí)現(xiàn)的接口,如果不支持則返回 0 。

            例如:

            void* CFastString::Dynamic_Cast(const char* pszTypename)
            {
            void * pRev;
            if(strcmp(pszTypename, "IFastString") == 0)
            {
            pRev = static_cast<IFastString*>(this);
            }
            else if(strcmp(pszTypename , "IOut") == 0)
            {
            pRev = static_cast<IOut*>(this);
            }
            else if(strcmp(pszTypename , "IExtent") == 0)
            {
            pRev = static_cast<IFastString*>(this);
            }
            else
            {
            return 0;
            }

            return pRev;
            }

            注意cast到IExtent的時(shí)候用了IFastString,因?yàn)镮FastString 和 IOut都是從IExtent繼承的,寫(xiě)IExtent的話不知道用哪個(gè),用虛擬繼承可以使CFastString對(duì)象只有一份IExtent,為啥不用呢? 你懂得。。。跟前面答案一樣,編譯器相關(guān)。

            最后一個(gè)問(wèn)題是delete的問(wèn)題,用戶需要記得為每一個(gè)對(duì)象調(diào)用一次delete方法,而指針cast來(lái)cast去,想記得對(duì)象被delete沒(méi)有很難啊! 怎么辦? 用引用計(jì)數(shù)吧,把每個(gè)指針當(dāng)做具有生命周期的實(shí)體,創(chuàng)建時(shí)候計(jì)數(shù)++,銷(xiāo)毀時(shí)候--,等到0的時(shí)候就delete對(duì)象。

            大功告成,通過(guò)vptr和vtbl的二進(jìn)制防火墻,我們做到了可重用的二進(jìn)制組件,組件變化客戶無(wú)需重新編譯 。

            posted @ 2011-08-21 16:19 rikisand 閱讀(2487) | 評(píng)論 (2)編輯 收藏

            2010年5月26日

            什么時(shí)候用memory-mapped files:

            1.System use it to load and execute .exe and dll files.

            2.Use memory-mapped files to access a data file on disk.

            3.allow multiple processes running on the same machine to share data with each other.

            ------------------------------------------------------------------------------------------------------

            用途一:使用mapping file executables and dlls

            當(dāng)調(diào)用createProcess時(shí)候,系統(tǒng)做了以下的事情:

            1.locates CreateProcess 中指定的the .exe file,失敗則return false

            2.創(chuàng)建新的process kernel object

            3.creates a private address space for new process

            4.reserves a region of address space large enough to contain the .exe file.The desired location of this region is specified by the .exe file itself.by default ,base address is 0x00400000 .You can change it by create your app .exe fiel using linker’s /BASE option.

            5.the systems notes that the physical storage baking the reserved region is in the .exe file on disk instread of the system’s paging file.(系統(tǒng)注意到,支持已保留區(qū)域的物理存儲(chǔ)區(qū)域是在磁盤(pán)上的.exe 文件而不是在系統(tǒng)頁(yè)面中)

            當(dāng)。exe 被mapped into the process address space,系統(tǒng)訪問(wèn).exe的一個(gè)區(qū)域,那里列出了.exe含有的dll,然后系統(tǒng)利用 LoadLibrary for each dlls。系統(tǒng)map dll時(shí)候,如果dll的 preferred base address 被占據(jù)或者不夠大,dllwill try to find another region of address space to reserve for the dll。如果dll 被設(shè)定了/Fixed when it build,也就是不支持重定位,那么加載失敗。

            如果加載dll或者exe 失敗,彈出對(duì)話框并且釋放申請(qǐng)的地址空間。

            after all .exe  dll mapped into the process address space, system can begin exec the .exe file starup code. the sys takes care of all paging,buffering, and caching. 例如,如果一段代碼訪問(wèn)了一個(gè)并不在主存的地址,那么一個(gè)錯(cuò)誤產(chǎn)生,系統(tǒng)察覺(jué)到錯(cuò)誤并且自動(dòng)的調(diào)入page of code from the files image into a page of RAM。

            the sys maps the page of ram to the proper location in the process address and allows the thread  to continue.

            當(dāng)為一個(gè)app創(chuàng)建第二個(gè)實(shí)例時(shí),系統(tǒng)只是簡(jiǎn)單的打開(kāi)另外一個(gè)memory-mapped view  of file-mapping object that identifies the exec files image and create a new process object and a new thread object.利用內(nèi)存映射文件,多個(gè)實(shí)例可以共享代碼和數(shù)據(jù)。實(shí)際上,file 是分為多個(gè)section ,多個(gè)節(jié)均對(duì)齊于頁(yè)邊界。如果一個(gè)instance of the app 修改了全局變量,系統(tǒng)應(yīng)用了copy-on-write 機(jī)制,復(fù)制修改的頁(yè)面,并更新實(shí)例的file-mapping view。當(dāng)我們調(diào)試程序時(shí)同樣的事情會(huì)發(fā)生,debuger modify code,sys use cow again。

            當(dāng)一個(gè)進(jìn)程被加載,系統(tǒng)檢查其所有映射文件頁(yè),系統(tǒng)將所有通常用cow保護(hù)的頁(yè)面提交給存儲(chǔ)系統(tǒng),這些頁(yè)面僅僅是被提交,當(dāng)文件被訪問(wèn)的時(shí)候,系統(tǒng)讀入相應(yīng)的頁(yè)面,如果頁(yè)面沒(méi)有被修改,那么他們可以被換出,如果已經(jīng)修改,系統(tǒng)將修改過(guò)的頁(yè)面轉(zhuǎn)入已經(jīng)提交的頁(yè)面之一(這點(diǎn)很晦澀啊 system swaps the modified page to one of the perviously committed pages in the paging file ,怎么翻譯呢~~~~ :(   )

            ------------------------------------------------------------------------------------------------------

            在可執(zhí)行文件或者dll中共享靜態(tài)變量

            ------------------------------------------------------------------------------------------------------

            內(nèi)存映射數(shù)據(jù)文件

            例子:要把一個(gè)文件所有字節(jié)倒置

            如果利用file mapping 我們告訴系統(tǒng)使用一個(gè)虛擬空間的區(qū)域來(lái)倒置文件,然后告訴把文件的第一個(gè)字節(jié)映射到保留空間的第一個(gè)字節(jié),然后就像處理內(nèi)存中的字符串一樣處理文件即可,引文系統(tǒng)會(huì)幫助你完成文件緩存以及調(diào)頁(yè)等工作。

            使用流程:

            1.創(chuàng)建一個(gè)file kernel object that identifies the file on disk that you want to use as a memory –mapped file

            2.創(chuàng)建一個(gè)file mapping kernel object 告訴系統(tǒng)文件的大小,以及你準(zhǔn)備如何訪問(wèn)文件

            3.告訴系統(tǒng)map all或者部分文件到你的進(jìn)程地址空間

            當(dāng)使用結(jié)束后要:

            1告訴系統(tǒng) unmap file-mapping kernel object form your process add

            2cloes filemapping kernel object

            3close file kernel object

            ---------

            具體步驟

            --1. 創(chuàng)建文件內(nèi)核對(duì)象

            CreateFile

            失敗返回 INVALID_HANDLE_VALUE = –1 一般來(lái)說(shuō)windows func 失敗return null這個(gè)比較特殊

            createfile dwdesiredAccess 需要設(shè)置為 GENERIC_READ 或者 GENERIC_WRITE 

            --2. 創(chuàng)建file-mapping 內(nèi)核對(duì)象

            CreatefileMapping(HANDLE,PSECURITY_ATTRIBUTES,DWORD fdwProtect,DWORD dwMaximumsizeHigh,DWORD dwMaximumSizeLow,PCTSTR pszName);

            第一個(gè)參數(shù)使用createfile 返回的handle。psa一般使用默認(rèn)null。當(dāng)創(chuàng)建一個(gè)file mapping object 時(shí)候,系統(tǒng)并不會(huì) 馬上保留一個(gè)地址空間,然后將file映射到這個(gè)區(qū)域。但很i,當(dāng)系統(tǒng)map時(shí)候,系統(tǒng)必須知道為physical storage分配什么樣的保護(hù)屬性,第三個(gè)參數(shù)指明了這些。

            后面兩個(gè)參數(shù)指明file的大小,ensure  enouth physical storage is available for the file-mapping object.

            high指明高32位,low指明低32位。如果想創(chuàng)建一個(gè)反應(yīng)現(xiàn)在文件大小的map,均傳0.

            pszName 用于與其它進(jìn)程共享內(nèi)存映射文件

            --3.將文件數(shù)據(jù)map to process address space

            使用這個(gè)函數(shù)

            PVOID MapViewOfFile(HANDLE hfileMappingObject,dwDesireaccess,dwFileOffsetHigh,dwFileOffsetLow,dwNumberOfbytestomap)

            文件沒(méi)必要一次全映射,一次映射一部分,這一部分成為一個(gè)view

            首先通過(guò)high和low 指定開(kāi)始映射的字節(jié)

            其次是指定映射多大,0則映射到文件尾部。

            --4.unmapping the file data from the process address space

            UnmapviewOfFile(PVOID pvBaseAdddress);

            參數(shù)使用mapview的返回值

            如果強(qiáng)制write back to disk 則使用 FlushViewOfFile(PVOID pvAddress,SIZE_T dwNumberOfBytesToFlush)

            第一個(gè)地址是想要開(kāi)始flush的地址

            --5.關(guān)閉filemapping object 以及file object

            -----------------------------------------------------------------------------------

            使用filemap 在進(jìn)程之間共享數(shù)據(jù)

            例子:

            app開(kāi)始時(shí)候,系統(tǒng)調(diào)用createfile to open .exe file onthe disk。sys call creatFileMapping to create filemapping object.然后系統(tǒng)調(diào)用  mapviewofffileEX (with sec_image flag to point out it is a pe file),So that the file’s image is mapped to the address of the first byte of exectuable code of this mapped view. System creates the primary thread , puts the address of the first byte of exec code of this mapped view in the thread instruction pointer,and then lets the cpu start exec the code.

            If user 再啟動(dòng)同一個(gè)app,sys 看到file-mapping已經(jīng)存在了,系統(tǒng)maps a view of file a second time,this time in the context of the newly created process address space.

            像所有內(nèi)核對(duì)象一樣,有三種方法共享他,繼承,命名對(duì)象以及賦值handle。

            ···頁(yè)文件支持的內(nèi)存映射文件

            許多應(yīng)用程序運(yùn)行是產(chǎn)生數(shù)據(jù)需要和其他進(jìn)程共享如果必須在硬盤(pán)建立文件才可以共享,那么效率很低。因此微軟提供了由system paging file 支持的 file mapping。不需要createfile ,只需要在調(diào)用createFilemapping 的時(shí)候傳進(jìn)一個(gè) INVALID_HANDLE_VALUE 作為hFile 參數(shù)即可。 映射文件大小同樣是由high 和low 參數(shù)決定的。

            `````稀疏提交的內(nèi)存映射文件

            --看來(lái)需要把虛擬內(nèi)存那章一起看看了~~~~

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            posted @ 2010-05-26 17:48 rikisand 閱讀(1050) | 評(píng)論 (0)編輯 收藏

            2010年5月25日

            A 簡(jiǎn)單的模擬 ,不過(guò)我寫(xiě)的很麻煩

            Problem

            On Unix computers, data is stored in directories. There is one root directory, and this might have several directories contained inside of it, each with different names. These directories might have even more directories contained inside of them, and so on.

            A directory is uniquely identified by its name and its parent directory (the directory it is directly contained in). This is usually encoded in a path, which consists of several parts each preceded by a forward slash ('/'). The final part is the name of the directory, and everything else gives the path of its parent directory. For example, consider the path:

            /home/gcj/finals
            
            This refers to the directory with name "finals" in the directory described by "/home/gcj", which in turn refers to the directory with name "gcj" in the directory described by the path "/home". In this path, there is only one part, which means it refers to the directory with the name "home" in the root directory.

            To create a directory, you can use the mkdir command. You specify a path, and thenmkdir will create the directory described by that path, but only if the parent directory already exists. For example, if you wanted to create the "/home/gcj/finals" and "/home/gcj/quals" directories from scratch, you would need four commands:

            mkdir /home
            mkdir /home/gcj
            mkdir /home/gcj/finals
            mkdir /home/gcj/quals
            

            Given the full set of directories already existing on your computer, and a set of new directories you want to create if they do not already exist, how many mkdir commands do you need to use?

            Input

            The first line of the input gives the number of test cases, T. T test cases follow. Each case begins with a line containing two integers N and M, separated by a space.

            The next N lines each give the path of one directory that already exists on your computer. This list will include every directory already on your computer other than the root directory. (The root directory is on every computer, so there is no need to list it explicitly.)

            The next M lines each give the path of one directory that you want to create.

            Each of the paths in the input is formatted as in the problem statement above. Specifically, a path consists of one or more lower-case alpha-numeric strings (i.e., strings containing only the symbols 'a'-'z' and '0'-'9'), each preceded by a single forward slash. These alpha-numeric strings are never empty.

            Output

            For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the number of mkdir you need.

            Limits

            1 ≤ T ≤ 100.
            No path will have more than 100 characters in it.
            No path will appear twice in the list of directories already on your computer, or in the list of directories you wish to create. A path may appear once in both lists however. (See example case #2 below).
            If a directory is listed as being on your computer, then its parent directory will also be listed, unless the parent is the root directory.
            The input file will be no longer than 100,000 bytes in total.

            Small dataset

            0 ≤ N ≤ 10.
            1 ≤ M ≤ 10.

            Large dataset

            0 ≤ N ≤ 100.
            1 ≤ M ≤ 100.

            Sample

            Input
            Output

            3
            0 2
            /home/gcj/finals
            /home/gcj/quals
            2 1
            /chicken
            /chicken/egg
            /chicken
            1 3
            /a
            /a/b
            /a/c
            /b/b

            Gluk的解法:

             set <string> S;
                    REP (i, n)
                    {
                        string s;
                        cin >> s;
                        S.insert(s);//已有的路徑用set表示
                    }
            
                    int res =0 ;
            
                    REP (i, m)
                    {
                        string s;
                        cin >> s;
                        vector <string> ss;
                        REP (j, s.size())
                            if(s[j] == '/')
                                s[j] = ' ';//用空格替換’/’,然后使用istringstream分隔各級(jí)目錄
                        istringstream iss (s);
                        while (iss >> s) {
                            ss.pb (s);
                        }
            
                        s = "";
                        REP (i, ss.size ())
                        {
                            s = s+"/"+ss[i];
                            if (S.find(s) == S.end())//依次加入各級(jí)目錄,/a  /a/b  /a/b/c 增加遞增的所有目錄
                            {
                                res ++;
                                S.insert(s);
                            }
                        }
                    }
            題目中的這一句
            If a directory is listed as being on your computer, then its parent directory will also be listed, unless the parent is the root directory.
            告訴我們?nèi)绻?a/b被list存在,那么/a也一定被list出來(lái)了 ,所以上面代碼可以不去分隔處理已經(jīng)給出的目錄
            yuhch123的解法
            struct node {
               map <string, node *> sons;//每個(gè)節(jié)點(diǎn),用map實(shí)現(xiàn)兒子節(jié)點(diǎn)
            };
            node *root;//一個(gè)根節(jié)點(diǎn)
            int T;
            int N, M;
            char tmp[100005];
            int ans = 0;
            void insert(node *cnt, char *tmp) {//在節(jié)點(diǎn)cnt處,插入tmp子樹(shù)
               int i;
               if (tmp[0] == 0)//為空則返回
                  return;
               assert(tmp[0] == '/');
               string str;
               for (i = 1; tmp[i] != '/' && tmp[i] != 0; i ++)//第一層
                  str += tmp[i];
               if (cnt -> sons.find(str) == cnt -> sons.end()) {//如果沒(méi)有這子樹(shù),則創(chuàng)建子樹(shù)
                  ans ++;//需要一次mkdir 
                  struct node *tmp2 = new node();
                  cnt -> sons[str] = tmp2;
               }
               insert(cnt -> sons[str], tmp + i);// 遞歸創(chuàng)建子樹(shù)
            }
            int main() {
               int i;
               int Case = 1;
               scanf("%d", &T);
               while (T --) {
                  scanf("%d%d", &N, &M);
                  root = new node();
                  for (i = 0; i < N; i ++) {
                 scanf("%s", tmp);
                 insert(root, tmp);
                  }
                  ans = 0;
                  for (i = 0; i < M; i ++) {
                 scanf("%s", tmp);
                 insert(root, tmp);
                  }
                  printf("Case #%d: %d\n", Case ++, ans);
               }
               return 0;
            }
            neal.wu的解法
            vector <string> parse (string s)
            {
                vector <string> v;
                string next = "";
                
                for (int i = 0; i < (int) s.length (); i++)
                {
                    next += s [i];
                    
                    if (i + 1 == (int) s.length () || s [i + 1] == '/')
                    {
                        v.push_back (next);
                        next = "";
                    }
                }
                
                return v;
            }
            
            set <string> direc;
            
            int insert (vector <string> v)
            {
                int count = 0;
                string s = "";
                
                for (int i = 0; i < (int) v.size (); i++)
                {
                    s += v [i];
                    count += direc.insert (s).second ? 1 : 0; //set返回一個(gè)pair<iterator,bool> bool指示插入是否成功   
             }
                
                return count;
            }
            
            int main ()
            {
                         freopen("d:\\input.txt","r",stdin);
              
                for (scanf ("%d", &T); TC <= T; TC++)
                {
                    scanf ("%d %d", &N, &M);
                    direc.clear ();
                    int make = 0;
                    char str [1000];
                    
                    for (int i = 0; i < N; i++)
                    {
                        do gets (str); while (strlen (str) == 0);//do gets 過(guò)濾回車(chē)空字符串
                        insert (parse (str));
                    }
                    
                    for (int i = 0; i < M; i++)
                    {
                        do gets (str); while (strlen (str) == 0);
                        make += insert (parse (str));
                    }
                    
                    printf ("Case #%d: %d\n", TC, make);
                }
                
                //system ("pause");
                return 0;
            }
            ploh的解法:
            int main(void)
            {freopen("d:\\input.txt","r",stdin);
              int T; cin >> T;
              for (int t = 1; t <= T; t++) {
                int ans = 0;
                set <string> have, want;
                int N, M;
                cin >> N >> M;
                for (int i = 0; i < N; i++) {
                  string path; cin >> path;
                  have.insert(path);
                }
                for (int i = 0; i < M; i++) {//用一個(gè)set保存所有需要加入的
                  string path; cin >> path;
                  want.insert(path);
                  for (int j = 1; j < path.length(); j++)
                if (path[j] == '/')
                  want.insert(path.substr(0, j));
                }
                for (set <string>::iterator it = want.begin(); it != want.end(); it++)//遍歷所有需要加入的,然后看是否存在
                  if (!have.count(*it))
                ans++;
                printf("Case #%d: %d\n", t, ans);
              }
            }
            
            

            posted @ 2010-05-25 23:29 rikisand 閱讀(367) | 評(píng)論 (0)編輯 收藏

            2010年5月1日

            這學(xué)期也開(kāi)始了好久,總結(jié)下。

            項(xiàng)目上:基本弄完了碼頭,算是結(jié)束了吧,剩下的工作是好好總結(jié)下學(xué)到的東西,把架構(gòu),用到的技術(shù)都理順了,方便之后面試回答。

            生活上:這半個(gè)月gf生病了,嘉定閔行兩頭跑果然很累,不過(guò)還好一直抽空看書(shū)。健康很重要~~ 要抓緊鍛煉身體了。本錢(qián)一定要掌握好。

            找實(shí)習(xí):先后筆試了摩根it和微軟。上周摩根給了電面,全英文的。完全沒(méi)有思想準(zhǔn)備的我正在在閔行g(shù)f那里照顧她,手邊什么書(shū)也沒(méi)有,項(xiàng)目資料也沒(méi)有,我的處女面就這樣“裸著”度過(guò)了,到現(xiàn)在還沒(méi)有消息,也不知道是不是默劇了。 微軟是上周六筆試的,也沒(méi)有消息,sigh~不知道是沒(méi)改完卷子還是杯具了~~

            關(guān)于實(shí)習(xí)的筆試和面試要專(zhuān)門(mén)寫(xiě)東西總結(jié)一下,方便以后查閱。

            1-4號(hào)放假,應(yīng)該不會(huì)有新的安排進(jìn)來(lái)(面試之類(lèi)的),得安排下事情

            上周把大話設(shè)計(jì)模式翻了一遍,利用這幾天要仔細(xì)的重新過(guò)一遍,每一個(gè)模式都寫(xiě)代碼實(shí)踐一下。

            然后想看看c++標(biāo)準(zhǔn)文檔,這個(gè)會(huì)很慢,可以選擇性的跳過(guò)一些東西,總共700多頁(yè),看前300頁(yè)就可以了,后面是介紹庫(kù)的。一天看75頁(yè),恩 ···比較困難·· 盡力吧

            其他的就不安排了,也做不完的。

            另外,之后學(xué)的東西,一定要及時(shí)用日志記下來(lái),否則時(shí)間長(zhǎng)了還要從頭學(xué)起`````

             

             

             

             

             

             

            posted @ 2010-05-01 14:31 rikisand 閱讀(330) | 評(píng)論 (0)編輯 收藏

            2010年4月7日

            良好的編程風(fēng)格是:new和delete 配套使用,即如果使用new [] 則使用delete []

            事實(shí)上,如果我們使用的是自定義類(lèi)型int char等,或者我們使用的是沒(méi)有內(nèi)存申請(qǐng)的類(lèi),我們使用 delete A;并不會(huì)發(fā)生什么不好的事情。

            這是由delete 的語(yǔ)義決定的。當(dāng)我們是申請(qǐng)一組對(duì)象時(shí)候,編譯器會(huì)加入內(nèi)存大小信息和此段內(nèi)存相關(guān)聯(lián)。因此當(dāng)我們delte A 時(shí),編譯器會(huì)按照內(nèi)存大小收回分給我們的內(nèi)存。顯然,如果是基本類(lèi)型或者沒(méi)有申請(qǐng)內(nèi)存的情況這樣的行為是良好的。但是如果我們?cè)谧越?lèi)型中申請(qǐng)了內(nèi)存~對(duì)不起,編譯器是不知道的,這些申請(qǐng)的內(nèi)存就是內(nèi)存泄露,隨著程序不斷進(jìn)行,堆不斷地被侵蝕·····

            這就是delete的第二個(gè)作用,他會(huì)施加析構(gòu)函數(shù)在我們申請(qǐng)的內(nèi)存上,如果我們delete A,只會(huì)在第一個(gè)上施加,而如果delete [] A;他會(huì)對(duì)數(shù)組中每一個(gè)元素進(jìn)行析構(gòu)~~

            so····

            試驗(yàn)很容易做,寫(xiě)兩個(gè)類(lèi),一個(gè)申請(qǐng)內(nèi)存,一個(gè)普通的類(lèi),然后循環(huán)申請(qǐng)大量數(shù)組,但是用 delete A 形式,然后看看內(nèi)存占用就行了

            posted @ 2010-04-07 10:42 rikisand 閱讀(518) | 評(píng)論 (1)編輯 收藏

            2010年4月4日

            數(shù)據(jù)對(duì)齊:是指數(shù)據(jù)所在的內(nèi)存地址必須是該數(shù)據(jù)長(zhǎng)度的整數(shù)倍。處理器可以直接訪問(wèn)對(duì)齊的數(shù)據(jù),而訪問(wèn)未對(duì)齊的數(shù)據(jù)會(huì)在內(nèi)部進(jìn)行一系列的調(diào)整,雖然可以正常處理,但是會(huì)降低運(yùn)行速度。例如一個(gè)處理器總線寬度為64位,那么地址必須為8的倍數(shù),也就是一次取出8個(gè)字節(jié)。如果我們可以保證所有double地址都為8的倍數(shù),那么可以用一個(gè)存儲(chǔ)器操作來(lái)讀或者寫(xiě)double了,否則我們可能需要執(zhí)行兩次存儲(chǔ)器訪問(wèn),因?yàn)閷?duì)象可能位于兩個(gè)8字節(jié)存儲(chǔ)器塊中

            對(duì)于結(jié)構(gòu)體也是一樣的例如 struct s2{int i;int j;char c;}; 如果我們把這個(gè)結(jié)構(gòu)打包成9個(gè)字節(jié),只要保證起始地址滿足4的對(duì)齊要求我們就可以保證i j的對(duì)齊,不過(guò)如果我們聲明了一個(gè)數(shù)組,那么元素地址成為 xd,xd+9,xd+18,xd+27 不滿足對(duì)齊了。因此我們呢要分配12個(gè)字節(jié)給這個(gè)結(jié)構(gòu)體

            更進(jìn)一步 :

            未對(duì)齊的數(shù)據(jù)會(huì)以不同方式給cpu帶來(lái)麻煩~

            1.如果一個(gè)變量被劃分到兩個(gè)緩存行,那么我們需要訪問(wèn)兩個(gè)緩存行才可以。

            2.一些simd指令總是要求對(duì)齊的指令,對(duì)于未對(duì)齊的指令,數(shù)據(jù)對(duì)齊也會(huì)影響這些指令的使用。

            posted @ 2010-04-04 16:00 rikisand 閱讀(443) | 評(píng)論 (3)編輯 收藏

            2010年3月26日

            Drainage Ditches
            Hal Burch

            Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.

            Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network. Note however, that there can be more than one ditch between two intersections.

            Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.

            PROGRAM NAME: ditch
            INPUT FORMAT

            Line 1:
            Two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream.

            Line 2..N+1:
            Each of N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

            SAMPLE INPUT (file ditch.in)
            5 4
            1 2 40
            1 4 20
            2 4 20
            2 3 30
            3 4 10
            
            OUTPUT FORMAT

            One line with a single integer, the maximum rate at which water may emptied from the pond.

            SAMPLE OUTPUT (file ditch.out)
            50
            最基本的網(wǎng)絡(luò)流
               1:  #include<iostream>
               2:  #include<fstream>
               3:  #include<string>
               4:  #include<vector>
               5:  #include<map>
               6:  #include<algorithm>
               7:  #include<sstream>
               8:  #include <cstring>
               9:  #include <queue>
              10:  using namespace std;
              11:  const int MAXN = 220;
              12:  const int infi = 0x7FFFFFFF;
              13:   int capacity[MAXN][MAXN], prenode[MAXN], flow[MAXN];
              14:   queue<int> mq; 
              15:   
              16:  int start, end, N;
              17:  void init(){
              18:      freopen("ditch.in","r",stdin);
              19:      //freopen("e:\\usaco\\ditch.in","r",stdin);
              20:      start = 1;  
              21:      scanf("%d %d",&N,&end); int c, s, t;
              22:      memset(capacity,0,sizeof(capacity));
              23:      for(int i=0;i<N;i++)
              24:      {
              25:          scanf("%d %d %d",&c,&s,&t);
              26:          capacity[c][s] += t; //兩個(gè)節(jié)點(diǎn)間不只有一條路
              27:      } 
              28:  }
              29:  int bfs(){//尋找增廣路徑
              30:      while(!mq.empty()) mq.pop(); 
              31:      mq.push(start);  //源節(jié)點(diǎn)入隊(duì)
              32:      //memset(flow,0,sizeof(flow));
              33:      memset(prenode,-1,sizeof(prenode)); //重置前向節(jié)點(diǎn)
              34:      prenode[start] = 0; flow[start]=infi; //源節(jié)點(diǎn)流量無(wú)限大
              35:      while(!mq.empty()){
              36:          int cur = mq.front(); 
              37:          mq.pop();
              38:          if(cur == end) break; //到達(dá)匯點(diǎn)結(jié)束路徑 
              39:          for(int i=1;i<=end;i++){ 
              40:              if(prenode[i]==-1 && capacity[cur][i]) //訪問(wèn)當(dāng)前節(jié)點(diǎn)所有未訪問(wèn)的相鄰節(jié)點(diǎn),更新flow
              41:              {
              42:                  prenode[i] = cur;
              43:                  flow[i] = (flow[cur]<capacity[cur][i]?flow[cur]:capacity[cur][i]);
              44:                  mq.push(i);
              45:              }
              46:          }
              47:      }
              48:      if(prenode[end]==-1)  //如果未找到增廣路徑返回-1
              49:          return -1;
              50:      return flow[end];
              51:  }
              52:  int Edmonds_Karp(){
              53:      int total = 0, pathcapacity;//pathcapacity 路徑增加量
              54:      while((pathcapacity = bfs()) != -1){//可以找到增廣路徑時(shí)候進(jìn)行循環(huán)
              55:          int cur = end;    //從匯點(diǎn)開(kāi)始增加逆向節(jié)點(diǎn)
              56:          while( cur != start ){
              57:              int t = prenode[cur] ;
              58:              capacity[t][cur] -= pathcapacity;
              59:              capacity[cur][t] += pathcapacity;
              60:              cur = t;
              61:          }
              62:          total += pathcapacity;//max_flow
              63:      }
              64:      return total;
              65:  }
              66:  void output(){
              67:      freopen("ditch.out","w",stdout);
              68:      //freopen("c:\\usaco\\ditch.out","w",stdout);
              69:      cout<<Edmonds_Karp()<<endl;
              70:  } 
              71:     int main()
              72:  {
              73:      init();  
              74:      output();
              75:      return 0;
              76:  }

            標(biāo)程:使用貪心法,尋找一條增廣路徑的時(shí)候不斷尋找cap最大的,未被訪問(wèn)的節(jié)點(diǎn)mloc;然后更新跟mloc相鄰的節(jié)點(diǎn)flow以

            及prenode信息.最后當(dāng)運(yùn)行到end時(shí)候,更新路徑節(jié)點(diǎn)capacity,同時(shí)增加max_flow.重復(fù)上述過(guò)程直到找不到增廣路徑

               1:  #include <stdio.h>
               2:  #include <string.h>
               3:   
               4:  #define MAXI 200
               5:   
               6:  /* total drain amount between intersection points */
               7:  int drain[MAXI][MAXI];
               8:  int nint; /* number of intersection points */
               9:   
              10:  int cap[MAXI]; /* amount of flow that can get to each node */
              11:  int vis[MAXI]; /* has this node been visited by Dijkstra's yet? */
              12:  int src[MAXI]; /* the previous node on the path from the source to here */
              13:   
              14:  int augment(void)
              15:   { /* run a Dijkstra's varient to find maximum augmenting path */
              16:    int lv;
              17:    int mloc, max;
              18:    int t;
              19:   
              20:    memset(cap, 0, sizeof(cap));
              21:    memset(vis, 0, sizeof(vis));
              22:   
              23:    cap[0] = 2000000000;
              24:    while (1)
              25:     {
              26:      /* find maximum unvisited node */
              27:      max = 0;
              28:      mloc = -1;
              29:      for (lv = 0; lv < nint; lv++)
              30:        if (!vis[lv] && cap[lv] > max)
              31:         {
              32:          max = cap[lv];
              33:      mloc = lv;
              34:         }
              35:      if (mloc == -1) return 0;
              36:      if (mloc == nint-1) break; /* max is the goal, we're done */
              37:   
              38:      vis[mloc] = -1; /* mark as visited */
              39:   
              40:      /* update neighbors, if going through this node improves the
              41:         capacity */
              42:      for (lv = 0; lv < nint; lv++)
              43:        if (drain[mloc][lv] > cap[lv] && max > cap[lv])
              44:         {
              45:          cap[lv] = drain[mloc][lv];
              46:      if (cap[lv] > max) cap[lv] = max;
              47:      src[lv] = mloc;
              48:         }
              49:     }
              50:    max = cap[nint-1];
              51:   
              52:    /* augment path, starting at end */
              53:    for (lv = nint-1; lv > 0; lv = src[lv])
              54:     {
              55:      t = src[lv];
              56:      drain[t][lv] -= max;
              57:      drain[lv][t] += max;
              58:     }
              59:    return max;
              60:   }
              61:   
              62:  int main(int argc, char **argv)
              63:   {
              64:    FILE *fout, *fin;
              65:    int lv;
              66:    int num;
              67:    int p1, p2, c;
              68:   
              69:    if ((fin = fopen("ditch.in", "r")) == NULL)
              70:     {
              71:      perror ("fopen fin");
              72:      exit(1);
              73:     }
              74:    if ((fout = fopen("ditch.out", "w")) == NULL)
              75:     {
              76:      perror ("fopen fout");
              77:      exit(1);
              78:     }
              79:   
              80:    fscanf (fin, "%d %d", &num, &nint);
              81:    while (num--)
              82:     {
              83:      fscanf (fin, "%d %d %d", &p1, &p2, &c);
              84:      p1--;
              85:      p2--;
              86:      drain[p1][p2] += c; /* note += handles two ditches between same points */
              87:     }
              88:   
              89:    /* max flow algorithm: augment while you can */
              90:    c = 0;
              91:    while ((p1 = augment()))
              92:      c += p1;
              93:    fprintf (fout, "%d\n", c);
              94:    return 0;
              95:   }

             

             

             

             

             

             

             

             

            posted @ 2010-03-26 13:04 rikisand 閱讀(421) | 評(píng)論 (0)編輯 收藏

            2010年3月25日

            最后一章~~拖了幾天,得趕緊記下了~~

            名字: On the cusp of the object model

            7.1 Template

            Template用的很少,這節(jié)中的有些東西比較晦澀,挑一些能理解的記下吧。剩下的等用的多了再回頭來(lái)看。

            Template的具現(xiàn)行為 template instantiation

            Template <calss T>class Point{

              public: enum Status{unallocated,normalized};Point(T x=0.0,T y=0.0);

            ~Point() ; void * operator new(size_t);private:static Point<T> *freelist

            static int chunksize; T _x,_y;

            };

            編譯器看到這樣的聲明,會(huì)有什么動(dòng)作??

            沒(méi)有。static data 不可用 enum 不可用 ,enum雖然類(lèi)型固定,但他只能和template point class 的某個(gè)實(shí)體來(lái)存取或操作。我們可以 point<float>::Status s;

            但是不能 point::status s; 因此我們可能想把enum抽離到一個(gè)非模板類(lèi)以避免多重拷貝。同樣道理,freelist 和chunksize對(duì)于程序而言也不可用。必須明確指定point<float>::freelist.也就是說(shuō)靜態(tài)數(shù)據(jù)成員是和特定類(lèi)型的類(lèi)綁定的而不是泛型的模板類(lèi)。但是如果定義一個(gè)指針不一定會(huì)具現(xiàn)出相應(yīng)的類(lèi),因?yàn)橐粋€(gè)指針,并不一定指向一個(gè)class object。編譯器不需要知道該class 相應(yīng)的任何member 或者數(shù)據(jù)或者

            內(nèi)存布局,所以沒(méi)有必要具現(xiàn)。但是如果是定義并初始化一個(gè)引用就真的會(huì)具現(xiàn)出一個(gè)實(shí)體,因?yàn)椴淮嬖诳找谩?/font>

            成員函數(shù)并不應(yīng)該被實(shí)體化,只有當(dāng)他被調(diào)用的時(shí)候才需要被具現(xiàn)出來(lái)。

            template<class T>

            class mumble{

            public: Muble(T t=1024):tt(t){ if(tt!=t)throw ex; }

            private: T tt;

            };

            上面的模板中出現(xiàn)錯(cuò)誤有,t=1024 不一定成功,!= 不一定定義

            這兩個(gè)錯(cuò)誤只有到具現(xiàn)操作結(jié)合具體類(lèi)型才能確定出來(lái)

            編譯器面對(duì)一個(gè)template聲明,在他被一組實(shí)際參數(shù)具現(xiàn)之前,只能實(shí)行以有限地錯(cuò)誤檢查,只有特定實(shí)體定義之后,才會(huì)發(fā)現(xiàn)一些與語(yǔ)法無(wú)關(guān)的但是十分明顯的錯(cuò)誤,這是技術(shù)上的一大問(wèn)題。

            Template 的名稱決議方式

            .h文件定義

            void out(int x){
                cout<<"out_by_class_define_scrope"<<endl;
            }
            template <class type>
            class A{
            public:
                void test1(){
                    out(m1);
                }
                void test2(){
                    out(m2);
                }
            private:
                int m1;
                type m2;
            };

            .cpp文件定義

            void out(double x){
                cout<<"out_by_class_instantiation_scrope"<<endl;
            }

            int main()
            {    
                A<double> a;
                a.test1();
                a.test2();

            }

            按照書(shū)中的說(shuō)法,如果一個(gè)函數(shù),參數(shù)類(lèi)型和type無(wú)關(guān)的話,應(yīng)該取他的scope of template declaration中定義的函數(shù),而反之取在他的instantiation中的那個(gè)。事實(shí)上在測(cè)試中發(fā)現(xiàn)

            MSVC 中 ,函數(shù)定義的決議是依照類(lèi)型的,如果有合適的函數(shù)比如type是double,此時(shí)如果定義處或者具現(xiàn)處有double型的函數(shù)定義,那么函數(shù)就會(huì)決議為那一個(gè)定義的~~~

            MEMber function的具現(xiàn)行為:

            編譯器如何確保只有一個(gè)vtable產(chǎn)生? 一種方法是 每一個(gè)virtual func地址都放在vtable中,如果取得函數(shù)地址,則表示virtual func 的定義必然出現(xiàn)在程序的某個(gè)地點(diǎn),否則程序無(wú)法連接成功。此外該函數(shù)只能有一個(gè)實(shí)體,否則也是連接不成功。那么,就把vtable放在定義了該class的第一個(gè)non-inline,nonpure virtual function的文件中吧。。(not so clear)

            在實(shí)現(xiàn)層面上,template 似乎拒絕全面自動(dòng)化,以手動(dòng)方式在個(gè)別的object module中完成預(yù)先的具現(xiàn)工作是一種有效率的方法。

            7.2異常處理

            為了維持執(zhí)行速度,編譯器可以在編譯時(shí)期建立起用于支持的數(shù)據(jù)結(jié)構(gòu)

            為了維持程序大小,編譯器可以在執(zhí)行期建立數(shù)據(jù)結(jié)構(gòu)

            c++ eH 主要由三個(gè)部分構(gòu)成:

            throw語(yǔ)句

            catch語(yǔ)句

            try語(yǔ)句,這些語(yǔ)句可能觸發(fā)catch子句起作用

            一個(gè)exception 被拋出時(shí)候,控制權(quán)會(huì)從函數(shù)調(diào)用釋放出來(lái),并尋找一個(gè)吻合的catch,如果沒(méi)有那么默認(rèn)的處理例程terminate()會(huì)被調(diào)用,控制權(quán)放棄后,堆棧中的每一個(gè)函數(shù)調(diào)用也被推離。每一個(gè)函數(shù)被推離堆棧的時(shí)候,函數(shù)的local class object 的dtor也會(huì)被調(diào)用。

            在程序不同段里,由于聲明不同的變量,一個(gè)區(qū)域可能因?yàn)樵趨^(qū)域內(nèi)發(fā)生exception的處理方式不同分成多個(gè)區(qū)段。

            在程序員層面,eh也改變了函數(shù)在資源上的管理。例如下面函數(shù)中更含有對(duì)一塊共享內(nèi)存的locking和unlocking操作 :

            void mumble(void * arena){

            Point *p= new point ;

            smlock(arena) ;

            //…..如果此時(shí)一個(gè)exception發(fā)生,問(wèn)題就產(chǎn)生了

            sumunlock(arena);

            delete p;

            }

            從語(yǔ)義上講,我們?cè)诤瘮?shù)退出堆棧之前,需要unlock共享內(nèi)存并delete p,我們需要這樣做:

            try{smlock(arena)} catch(…){

                smunlock(arena); delete p; throw;

            }

            new不需要放在try段里,因?yàn)椋绻鹡ew發(fā)生了exception,heap中的內(nèi)存并沒(méi)有分配,point的ctor沒(méi)有調(diào)用,如果在ctor中exception,那么piont的任何構(gòu)造好的合成物也會(huì)自動(dòng)解構(gòu)掉,heap也會(huì)自動(dòng)釋放掉。

            處理這種資源管理問(wèn)題,建議: 把資源需求封裝在一個(gè)class object 體內(nèi),并由dtor釋放資源.

            auto_ptr<point> ph (new point); smlock sm(arena);//如果此時(shí)exception 沒(méi)有問(wèn)題

            // 不需要明確的unlock 和delete

            // local dtor 會(huì)在這里被調(diào)用 sm.SMlock::~smlock(); ph.auto_ptr<point>::~auto_ptr<point>

            Exception handling 的支持:

            1.檢驗(yàn)發(fā)生throw操作的函數(shù)

            2.決定throw是否發(fā)生在try區(qū)段里

            3.如果是編譯器必須把exception type 拿來(lái)和catch比較

            4.吻合的話控制權(quán)交給catch

            5.如果throw不發(fā)生在try段或者沒(méi)有吻合的,系統(tǒng)會(huì)摧毀所有active local object b從堆棧把當(dāng)前函數(shù)unwind掉 ,跳出到程序堆棧的下一個(gè)函數(shù)去,然后重復(fù)上述步驟

            當(dāng)一個(gè)實(shí)際對(duì)象在程序執(zhí)行時(shí)被拋出,exception object會(huì)被產(chǎn)生出來(lái)并通常放在相同形式的exception 數(shù)據(jù)堆棧中。

            catch(expoint p){

               //do sth

               throw;

            }

            以及一個(gè)exception object 類(lèi)型為 exVertex 派生自 expoint ,這兩種類(lèi)型都吻合,catch會(huì)怎么做

            以exception object作為初值,像函數(shù)參數(shù)一樣會(huì)有一個(gè)local copy,如果p是一個(gè)object而不是一個(gè)reference ,內(nèi)容被拷貝的時(shí)候,這個(gè)object的非expoint部分會(huì)被切掉,如果有vptr 會(huì)被設(shè)定為expoint的vptr,如果被再次丟出呢?丟出p需要再產(chǎn)生另外一個(gè)exception 臨時(shí)對(duì)象,丟出原來(lái)的異常 ,之前的修改統(tǒng)統(tǒng)作廢。但是如果 catch(expoint& p);怎么樣呢。 任何對(duì)這個(gè)object的改變都會(huì)繁殖到之后的catch語(yǔ)句總。

            c++ 編譯器為了支持EH付出的代價(jià)最大,某種程度是因?yàn)閳?zhí)行期的天性以及對(duì)底層硬件的依賴。

            7.3 RTTI

            RTTI是Except handling的一個(gè)附屬產(chǎn)品,因?yàn)槲覀冃枰峁┠撤N查詢exception objects的方法,用來(lái)得到exception的實(shí)際類(lèi)型。

            在向下轉(zhuǎn)型問(wèn)題上,如果要保證其安全性,那么必須在執(zhí)行期對(duì)指針有所查詢,看看它到底指向什么類(lèi)型的對(duì)象。那么我們需要額外的空間存儲(chǔ)類(lèi)型信息,通常是一個(gè)指針,指某個(gè)類(lèi)型信息節(jié)點(diǎn)。

            需要額外的時(shí)間以決定執(zhí)行期的類(lèi)型。

            沖突發(fā)生在:

            1.程序員大量的使用了多臺(tái),并需要大量的downcast操作

            2.程序員使用內(nèi)建的數(shù)據(jù)類(lèi)型和非多態(tài),他不需要額外負(fù)擔(dān)帶來(lái)的便利

            那么如何了解程序員的需要呢?? 策略是一個(gè)具有多態(tài)性性質(zhì)的class,也就是具有內(nèi)涵繼承或者聲明 virtual func的類(lèi)需要rtti支持。

            這樣所有多態(tài)類(lèi)維護(hù)一個(gè)vptr。額外負(fù)擔(dān)降低到:每一個(gè)class object多花費(fèi)一個(gè)指針,指針只被設(shè)定一次,而且是編譯器靜態(tài)設(shè)定。

            down_cast

            if(pfct pf = dynamic_cast< pfct >(pt))….

            ((type_info*)(pt->vptr[0]))->type_descripter;

            Reference --------Pointer

            dynamic_cast執(zhí)行在ptr上 失敗返回0,如果實(shí)行在ref上。由于ref不能被賦予null,也就是沒(méi)有空引用。如果我們把一個(gè)ref設(shè)為0會(huì)引發(fā)臨時(shí)對(duì)象產(chǎn)生,然后用0初始化它,使ref成為這個(gè)臨時(shí)對(duì)象的別名。因此此時(shí)失敗了會(huì)產(chǎn)生一個(gè)bad_cast exception。

            typeid的參數(shù)可以使引用,對(duì)象或者是類(lèi)型

            事實(shí)上,type_info 也適用內(nèi)建類(lèi)型,這對(duì)于eh機(jī)制有必要

            例如 int ex_errno; throw ex_errno;

            其中int類(lèi)型 int *ptr; if(typeid(ptr) == typeid(int*));

            ----------------------全書(shū)筆記到此結(jié)束 --------------------------------s

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            posted @ 2010-03-25 21:09 rikisand 閱讀(423) | 評(píng)論 (0)編輯 收藏

            2010年3月22日

             

            第一組

            1.燒一根不均勻的繩,從頭燒到尾總共需要1個(gè)小時(shí)。現(xiàn)在有若干條材質(zhì)相同的繩子,問(wèn)如何用燒繩的方法來(lái)計(jì)時(shí)一個(gè)小時(shí)十五分鐘呢?
            2.你有一桶果凍,其中有黃色、綠色、紅色三種,閉上眼睛抓取同種顏色的兩個(gè)。抓取多少個(gè)就可以確定你肯定有兩個(gè)同一顏色的果凍?
            3.如果你有無(wú)窮多的水,一個(gè)3公升的提捅,一個(gè)5公升的提捅,兩只提捅形狀上下都不均勻,問(wèn)你如何才能準(zhǔn)確稱出4公升的水?
            4.一個(gè)岔路口分別通向誠(chéng)實(shí)國(guó)和說(shuō)謊國(guó)。來(lái)了兩個(gè)人,已知一個(gè)是誠(chéng)實(shí)國(guó)的,另一個(gè)是說(shuō)謊國(guó)的。誠(chéng)實(shí)國(guó)永遠(yuǎn)說(shuō)實(shí)話,說(shuō)謊國(guó)永遠(yuǎn)說(shuō)謊話。現(xiàn)在你要去說(shuō)謊國(guó),但不知道應(yīng)該走哪條路,需要問(wèn)這兩個(gè)人。請(qǐng)問(wèn)應(yīng)該怎么問(wèn)?
            5.12個(gè)球一個(gè)天平,現(xiàn)知道只有一個(gè)和其它的重量不同,問(wèn)怎樣稱才能用三次就找到那個(gè)球。13個(gè)呢?(注意此題并未說(shuō)明那個(gè)球的重量是輕是重,所以需要仔細(xì)考慮)
            6.在9個(gè)點(diǎn)上畫(huà)10條直線,要求每條直線上至少有三個(gè)點(diǎn)?
            7.在一天的24小時(shí)之中,時(shí)鐘的時(shí)針、分針和秒針完全重合在一起的時(shí)候有幾次?都分別是什么時(shí)間?你怎樣算出來(lái)的?
            8.怎么樣種植4棵樹(shù)木,使其中任意兩棵樹(shù)的距離相等?

            第二組

            1.為什么下水道的蓋子是圓的?
            2.中國(guó)有多少輛汽車(chē)?
            3.將汽車(chē)鑰匙插入車(chē)門(mén),向哪個(gè)方向旋轉(zhuǎn)就可以打開(kāi)車(chē)鎖?
            4.如果你要去掉中國(guó)的34個(gè)省(含自治區(qū)、直轄市和港澳特區(qū)及臺(tái)灣省)中的任何一個(gè),你會(huì)去掉哪一個(gè),為什么?
            5.多少個(gè)加油站才能滿足中國(guó)的所有汽車(chē)?
            6.想象你站在鏡子前,請(qǐng)問(wèn),為什么鏡子中的影象可以顛倒左右,卻不能顛倒上下?
            7.為什么在任何旅館里,你打開(kāi)熱水,熱水都會(huì)瞬間傾瀉而出?
            8.你怎樣將Excel的用法解釋給你的奶奶聽(tīng)?
            9.你怎樣重新改進(jìn)和設(shè)計(jì)一個(gè)ATM銀行自動(dòng)取款機(jī)?
            10.如果你不得不重新學(xué)習(xí)一種新的計(jì)算機(jī)語(yǔ)言,你打算怎樣著手來(lái)開(kāi)始?
            11.如果你的生涯規(guī)劃中打算在5年內(nèi)受到獎(jiǎng)勵(lì),那獲取該項(xiàng)獎(jiǎng)勵(lì)的動(dòng)機(jī)是什么?觀眾是誰(shuí)?
            12.如果微軟告訴你,我們打算投資五百萬(wàn)美元來(lái)啟動(dòng)你的投資計(jì)劃,你將開(kāi)始什么樣商業(yè)計(jì)劃?為什么?
            13.如果你能夠?qū)⑷澜绲碾娔X廠商集合在一個(gè)辦公室里,然后告訴他們將被強(qiáng)迫做一件事,那件事將是什么?

            第三組

            1.你讓工人為你工作7天,回報(bào)是一根金條,這個(gè)金條平分成相連的7段,你必須在每天結(jié)束的時(shí)候給他們一段金條。如果只允許你兩次把金條弄斷,你如何給你的工人付費(fèi)?
            2.有一輛火車(chē)以每小時(shí)15公里的速度離開(kāi)北京直奔廣州,同時(shí)另一輛火車(chē)每小時(shí)20公里的速度從廣州開(kāi)往北京。如果有一只鳥(niǎo),以30公里每小時(shí)的速度和兩輛火車(chē)同時(shí)啟動(dòng),從北京出發(fā),碰到另一輛車(chē)后就向相反的方向返回去飛,就這樣依次在兩輛火車(chē)之間來(lái)回地飛,直到兩輛火車(chē)相遇。請(qǐng)問(wèn),這只鳥(niǎo)共飛行了多長(zhǎng)的距離?
            3.你有四個(gè)裝藥丸的罐子,每個(gè)藥丸都有一定的重量,被污染的藥丸是沒(méi)被污染的藥丸的重量+1。只稱量一次,如何判斷哪個(gè)罐子的藥被污染了?
            4.門(mén)外三個(gè)開(kāi)關(guān)分別對(duì)應(yīng)室內(nèi)三盞燈,線路良好,在門(mén)外控制開(kāi)關(guān)時(shí)候不能看到室內(nèi)燈的情況,現(xiàn)在只允許進(jìn)門(mén)一次,確定開(kāi)關(guān)和燈的對(duì)應(yīng)關(guān)系?
            5.人民幣為什么只有1、2、5、10的面值?
            6.你有兩個(gè)罐子以及50個(gè)紅色彈球和50個(gè)藍(lán)色彈球,隨機(jī)選出一個(gè)罐子, 隨機(jī)選出一個(gè)彈球放入罐子,怎么給出紅色彈球最大的選中機(jī)會(huì)?在你的計(jì)劃里,得到紅球的幾率是多少?
            7.給你兩顆6面色子,可以在它們各個(gè)面上刻上0-9任意一個(gè)數(shù)字,要求能夠用它們拼出任意一年中的日期數(shù)值

            第四組

            第一題 . 五個(gè)海盜搶到了100顆寶石,每一顆都一樣大小和價(jià)值連城。他們決定這么分:
            抽簽決定自己的號(hào)碼(1、2、3、4、5)
            首先,由1號(hào)提出分配方案,然后大家表決,當(dāng)且僅當(dāng)超過(guò)半數(shù)的人同意時(shí),按照他的方案
            進(jìn)行分配,否則將被扔進(jìn)大海喂鯊魚(yú)
            如果1號(hào)死后,再由2號(hào)提出分配方案,然后剩下的4人進(jìn)行表決,當(dāng)且僅當(dāng)超過(guò)半數(shù)的人同
            意時(shí),按照他的方案進(jìn)行分配,否則將被扔入大海喂鯊魚(yú)
            依此類(lèi)推
            條件:每個(gè)海盜都是很聰明的人,都能很理智地做出判斷,從而做出選擇。
            問(wèn)題:第一個(gè)海盜提出怎樣的分配方案才能使自己的收益最大化?

            第二題 . 一道關(guān)于飛機(jī)加油的問(wèn)題,已知:
            每個(gè)飛機(jī)只有一個(gè)油箱,
            飛機(jī)之間可以相互加油(注意是相互,沒(méi)有加油機(jī))
            一箱油可供一架飛機(jī)繞地球飛半圈,
            問(wèn)題:
            為使至少一架飛機(jī)繞地球一圈回到起飛時(shí)的飛機(jī)場(chǎng),至少需要出動(dòng)幾架飛機(jī)?(所有飛機(jī)從同一機(jī)場(chǎng)起飛,而且必須安全返回機(jī)場(chǎng),不允許中途降落,中間沒(méi)有飛機(jī)場(chǎng))

            第三題. 汽車(chē)加油問(wèn)題
            一輛載油500升的汽車(chē)從A開(kāi)往1000公里外的B,已知汽車(chē)每公里耗油量為1升,A處有無(wú)窮多的油,其他任何地點(diǎn)都沒(méi)有油,但該車(chē)可以在任何地點(diǎn)存放油以備中轉(zhuǎn),問(wèn)從A到B最少需要多少油

            第四題. 擲杯問(wèn)題
            一種杯子,若在第N層被摔破,則在任何比N高的樓層均會(huì)破,若在第M層不破,則在任何比M低的樓層均會(huì)破,給你兩個(gè)這樣的杯子,讓你在100層高的樓層中測(cè)試,要求用最少的測(cè)試次數(shù)找出恰巧會(huì)使杯子破碎的樓層。

            第五題. 推理游戲
            教授選出兩個(gè)從2到9的數(shù),把它們的和告訴學(xué)生甲,把它們的積告訴學(xué)生乙,讓他們輪流猜這兩個(gè)數(shù)
            甲說(shuō):“我猜不出”
            乙說(shuō):“我猜不出”
            甲說(shuō):“我猜到了”
            乙說(shuō):“我也猜到了”
            問(wèn)這兩個(gè)數(shù)是多少

            第六題. 病狗問(wèn)題
            一個(gè)住宅區(qū)內(nèi)有100戶人家,每戶人家養(yǎng)一條狗,每天傍晚大家都在同一個(gè)地方遛狗。已知這些狗中有一部分病狗,由于某種原因,狗的主人無(wú)法判斷自己的狗是否是病狗,卻能夠分辨其他的狗是否有病,現(xiàn)在,上級(jí)傳來(lái)通知,要求住戶處決這些病狗,并且不允許指認(rèn)他人的狗是病狗(就是只能判斷自己的),過(guò)了7天之后,所有的病狗都被處決了,問(wèn),一共有幾只病狗?為什么?

            第七題. U2合唱團(tuán)在17分鐘內(nèi)得趕到演唱會(huì)場(chǎng),途中必需跨過(guò)一座橋,四個(gè)人從橋的同一端出發(fā),你得幫助他們到達(dá)另一端,天色很暗,而他們只有一只手電筒。一次同時(shí)最多可以有兩人一起過(guò)橋,而過(guò)橋的時(shí)候必須持有手電筒,所以就得有人把手電筒帶來(lái)帶去,來(lái)回橋兩端。手電筒是不能用丟的方式來(lái)傳遞的。四個(gè)人的步行速度各不同,若兩人同行則以較慢者的速度為準(zhǔn)。BONO需花1分鐘過(guò)橋,EDGE需花2分鐘過(guò)橋,ADAM需花5分鐘過(guò)橋,LARRY需花10分鐘過(guò)橋,他們要如何在17分鐘內(nèi)過(guò)橋呢?

            第八題. 監(jiān)獄里有100個(gè)房間,每個(gè)房間內(nèi)有一囚犯。一天,監(jiān)獄長(zhǎng)說(shuō),你們獄房外有一電燈,你們?cè)诜棚L(fēng)時(shí)可以控制這個(gè)電燈(熄或亮)。每天只能有一個(gè)人出來(lái)放風(fēng),并且防風(fēng)是隨機(jī)的。如果在有限時(shí)間內(nèi),你們中的某人能對(duì)我說(shuō):“我敢保證,現(xiàn)在每個(gè)人都已經(jīng)至少放過(guò)一次風(fēng)了。”我就放了你們!問(wèn)囚犯?jìng)円扇∈裁床呗圆拍鼙槐O(jiān)獄長(zhǎng)放掉?如果采用了這種策略,大致多久他們可以被釋放?

            第五組

            1.某手機(jī)廠家由于設(shè)計(jì)失誤,有可能造成電池壽命比原來(lái)設(shè)計(jì)的壽命短一半(不是沖放電時(shí)
            間),解決方案就是免費(fèi)更換電池或給50元購(gòu)買(mǎi)該廠家新手機(jī)的折換券。請(qǐng)給所有已購(gòu)買(mǎi)的
            用戶寫(xiě)信告訴解決方案。
            2.一高層領(lǐng)導(dǎo)在參觀某博物館時(shí),向博物館館員小王要了一塊明代的城磚作為紀(jì)念,按國(guó)家
            規(guī)定,任何人不得將博物館收藏品變?yōu)樗接小2┪镳^館長(zhǎng)需要如何寫(xiě)信給這位領(lǐng)導(dǎo),將城磚
            取回。
            3.營(yíng)業(yè)員小姐由于工作失誤,將2萬(wàn)元的筆記本電腦以1.2萬(wàn)元錯(cuò)賣(mài)給李先生,王小姐的經(jīng)理
            怎么寫(xiě)信給李先生試圖將錢(qián)要回來(lái)?
            4.給你一款新研制的手機(jī),如果你是測(cè)試組的組長(zhǎng),你會(huì)如何測(cè)試?
            5.如何為函數(shù)int atoi(const char * pstr)編寫(xiě)測(cè)試向量?

            第六組

            1.鏈表和數(shù)組的區(qū)別在哪里?
            2.編寫(xiě)實(shí)現(xiàn)鏈表排序的一種算法。說(shuō)明為什么你會(huì)選擇用這樣的方法?
            3.編寫(xiě)實(shí)現(xiàn)數(shù)組排序的一種算法。說(shuō)明為什么你會(huì)選擇用這樣的方法?
            4.請(qǐng)編寫(xiě)能直接實(shí)現(xiàn)char * strcpy(char * pstrDest,const char * pstrSource)函數(shù)功能的代碼。
            5.編寫(xiě)反轉(zhuǎn)字符串的程序,要求優(yōu)化速度、優(yōu)化空間。
            6.在鏈表里如何發(fā)現(xiàn)循環(huán)鏈接?
            7.給出洗牌的一個(gè)算法,并將洗好的牌存儲(chǔ)在一個(gè)整形數(shù)組里。
            8.寫(xiě)一個(gè)函數(shù),檢查字符是否是整數(shù),如果是,返回其整數(shù)值。(或者:怎樣只用4行代碼
            9.給出一個(gè)函數(shù)來(lái)輸出一個(gè)字符串的所有排列。
            10.請(qǐng)編寫(xiě)實(shí)現(xiàn)void * malloc(int)內(nèi)存分配函數(shù)功能一樣的代碼。
            11.給出一個(gè)函數(shù)來(lái)復(fù)制兩個(gè)字符串A和B。字符串A的后幾個(gè)字節(jié)和字符串B的前幾個(gè)字節(jié)重疊。
            12.怎樣編寫(xiě)一個(gè)程序,把一個(gè)有序整數(shù)數(shù)組放到二叉樹(shù)中?
            13.怎樣從頂部開(kāi)始逐層打印二叉樹(shù)結(jié)點(diǎn)數(shù)據(jù)?請(qǐng)編程。
            14.怎樣把一個(gè)鏈表掉個(gè)順序(也就是反序,注意鏈表的邊界條件并考慮空鏈表)? --
            15.請(qǐng)編寫(xiě)能直接實(shí)現(xiàn)int atoi(const char * pstr)函數(shù)功能的代碼。

            ---------------------------------------------------------------------------------------

            第一組題答案:

            1)三根繩,第一根點(diǎn)燃兩端,第二根點(diǎn)燃一端,第三根不點(diǎn)
            第一根繩燒完(30分鐘)后,點(diǎn)燃第二根繩的另一端,第二根繩燒完(45分鐘)后,點(diǎn)燃第三根繩子兩端,第三根繩燒完(1小時(shí)15分)后,計(jì)時(shí)完成
            2)根據(jù)抽屜原理,4個(gè)
            3)3升裝滿;3升-〉5升(全注入);3升裝滿;3升-〉5升(剩1升);5升倒掉;3升-〉5升(注入1升);3升裝滿;3升-〉5升;完成(另:可用回溯法編程求解)
            4)問(wèn)其中一人:另外一個(gè)人會(huì)說(shuō)哪一條路是通往誠(chéng)實(shí)國(guó)的?回答者所指的那條路必然是通往說(shuō)謊國(guó)的。
            5)12個(gè)球:
            第一次:4,4 如果平了:
              那么剩下的球中取3放左邊,取3個(gè)好球放右邊,稱:
                如果左邊重,那么取兩個(gè)球稱一下,哪個(gè)重哪個(gè)是次品,平的話第三個(gè)重,是次品,輕的話同理
                如果平了,那么剩下一個(gè)次品,還可根據(jù)需要稱出次品比正品輕或者重
            如果不平:
              那么不妨設(shè)左邊重右邊輕,為了便于說(shuō)明,將左邊4顆稱為重球,右邊4顆稱為輕球,剩下4顆稱為好球
              取重球2顆,輕球2顆放在左側(cè),右側(cè)放3顆好球和一顆輕球
              如果左邊重
                  稱那兩顆重球,重的一個(gè)次品,平的話右邊輕球次品
              如果右邊重
                  稱左邊兩顆輕球,輕的一個(gè)次品
              如果平
                  稱剩下兩顆重球,重的一個(gè)次品,平的話剩下那顆輕球次品
            13個(gè)球:
            第一次:4,4,如果平了
              剩5顆球用上面的方法仍舊能找出次品,只是不能知道次品是重是輕
            如果不平,同上
            6)
            o   o   o
              o o o
            o   o   o
            7)
            23次,因?yàn)榉轴樢D(zhuǎn)24圈,時(shí)針才能轉(zhuǎn)1圈,而分針和時(shí)針重合兩次之間的間隔顯然>1小時(shí),它們有23次重合機(jī)會(huì),每次重合中秒針有一次重合機(jī)會(huì),所以是23次
            重合時(shí)間可以對(duì)照手表求出,也可列方程求出
            8)
            在地球表面種樹(shù),做一個(gè)地球內(nèi)接的正四面體,內(nèi)接點(diǎn)即為所求

            第二組 無(wú)標(biāo)準(zhǔn)答案

            第三組

            1. 分成1,2,4三段,第一天給1,第二天給2取回1,第3天給1,第4天給4取回1、2,第5天給1,第6天給2取回1,第七天給1
            2. 求出火車(chē)相遇時(shí)間,鳥(niǎo)速乘以時(shí)間就是鳥(niǎo)飛行的距離
            3. 四個(gè)罐子中分別取1,2,3,4顆藥丸,稱出比正常重多少,即可判斷出那個(gè)罐子的藥被污染
            4. 三個(gè)開(kāi)關(guān)分別:關(guān),開(kāi),開(kāi)10分鐘,然后進(jìn)屋,暗且涼的為開(kāi)關(guān)1控制的燈,亮的為開(kāi)關(guān)2控制的燈,暗且熱的為開(kāi)關(guān)3控制的燈
            5. 因?yàn)榭梢杂?,2,5,10組合成任何需要的貨幣值,日常習(xí)慣為10進(jìn)制
            6. 題意不理解...*_*
            7. 012345 0126(9)78

            第四組 都是很難的題目

            第一題:97 0 1 2 0 或者 97 0 1 0 2 (提示:可用逆推法求出)

            第二題:3架飛機(jī)5架次,飛法:
            ABC 3架同時(shí)起飛,1/8處,C給AB加滿油,C返航,1/4處,B給A加滿油,B返航,A到達(dá)1/2處,C從機(jī)場(chǎng)往另一方向起飛,3/4處,C同已經(jīng)空油箱的A平分剩余油量,同時(shí)B從機(jī)場(chǎng)起飛,AC到7/8處同B平分剩余油量,剛好3架飛機(jī)同時(shí)返航。所以是3架飛機(jī)5架次。

            第三題:需要建立數(shù)學(xué)模型
            (提示,嚴(yán)格證明該模型最優(yōu)比較麻煩,但確實(shí)可證,大膽猜想是解題關(guān)鍵)
            題目可歸結(jié)為求數(shù)列 an=500/(2n+1) n=0,1,2,3......的和Sn什么時(shí)候大于等于1000,解得n>6
            當(dāng)n=6時(shí),S6=977.57
            所以第一個(gè)中轉(zhuǎn)點(diǎn)離起始位置距離為1000-977.57=22.43公里
            所以第一次中轉(zhuǎn)之前共耗油 22.43*(2*7+1)=336.50升
            此后每次中轉(zhuǎn)耗油500升
            所以總耗油量為7*500+336.50=3836.50升

            第四題:需要建立數(shù)學(xué)模型
            題目可歸結(jié)為求自然數(shù)列的和S什么時(shí)候大于等于100,解得n>13
            第一個(gè)杯子可能的投擲樓層分別為:14,27,39,50,60,69,77,84,90,95,99,100

            第五題:3和4(可嚴(yán)格證明)
            設(shè)兩個(gè)數(shù)為n1,n2,n1>=n2,甲聽(tīng)到的數(shù)為n=n1+n2,乙聽(tīng)到的數(shù)為m=n1*n2
            證明n1=3,n2=4是唯一解
            證明:要證以上命題為真,不妨先證n=7
            1)必要性:
               i) n>5 是顯然的,因?yàn)閚<4不可能,n=4或者n=5甲都不可能回答不知道
               ii) n>6 因?yàn)槿绻鹡=6的話,那么甲雖然不知道(不確定2+4還是3+3)但是無(wú)論是2,4還是3,3乙都不可能說(shuō)不知道(m=8或者m=9的話乙說(shuō)不知道是沒(méi)有道理的)
              iii) n<8 因?yàn)槿绻鹡>=8的話,就可以將n分解成 n=4+x 和 n=6+(x-2),那么m可以是4x也可以是6(x-2)而4x=6(x-2)的必要條件是x=6即n=10,那樣n又可以分解成8+2,所以總之當(dāng)n>=8時(shí),n至少可以分解成兩種不同的合數(shù)之和,這樣乙說(shuō)不知道的時(shí)候,甲就沒(méi)有理由馬上說(shuō)知道。
               以上證明了必要性
            2)充分性
                當(dāng)n=7時(shí),n可以分解成2+5或3+4
                顯然2+5不符合題意,舍去,容易判斷出3+4符合題意,m=12,證畢
            于是得到n=7 m=12 n1=3 n2=4是唯一解。

            第六題:7只(數(shù)學(xué)歸納法證明)
            1)若只有1只病狗,因?yàn)椴」分魅丝床坏接衅渌」罚厝粫?huì)知道自己的狗是病狗(前提是一定存在病狗),所以他會(huì)在第一天把病狗處決。
            2)設(shè)有k只病狗的話,會(huì)在第k天被處決,那么,如果有k+1只,病狗的主人只會(huì)看到k只病狗,而第k天沒(méi)有人處決病狗,病狗主人就會(huì)在第k+1天知道自己的狗是病狗,于是病狗在第k+1天被處決
            3)由1)2)得,若有n只病狗,必然在第n天被處決

            第七題:(提示:可用圖論方法解決)
            BONO&EDGE過(guò)(2分),BONO將手電帶回(1分),ADAM&LARRY過(guò)(10分),EDGE將手電帶回(2分),BONO&EDGE過(guò)(2分) 2+1+10+2+2=17分鐘

            第八題:
            約定好一個(gè)人作為報(bào)告人(可以是第一個(gè)放風(fēng)的人)
            規(guī)則如下:
            1、報(bào)告人放風(fēng)的時(shí)候開(kāi)燈并數(shù)開(kāi)燈次數(shù)
            2、其他人第一次遇到開(kāi)著燈放風(fēng)時(shí),將燈關(guān)閉
            3、當(dāng)報(bào)告人第100次開(kāi)燈的時(shí)候,去向監(jiān)獄長(zhǎng)報(bào)告,要求監(jiān)獄長(zhǎng)放人......
            按照概率大約30年后(10000天)他們可以被釋放

            第五組無(wú)標(biāo)準(zhǔn)答案

            第六組部分題參考答案:
            4.
            char * strcpy(char * pstrDest,const char * pstrSource)
            {
            assert((pstrDest!=NULL)&&(pstrSource!=NULL));

            char * pstr=pstrDest;
            while((*(pstrDest++)=*(pstrSource++))!='\0');
                    return pstr;
            }
            5.
            char * strrev(char * pstr)
            {
            assert(pstr!=NULL);
            char * p=pstr;
            char * pret=pstr;
            while(*(p++)!='\0');
            p--;
            char tmp;
            while(p>pstr)
            {
              tmp=*p;
              *(p--)=*(pstr);
              *(pstr++)=tmp; 
            }
            return pret;

            posted @ 2010-03-22 23:21 rikisand 閱讀(212) | 評(píng)論 (0)編輯 收藏

            2010年3月19日

            執(zhí)行期語(yǔ)義學(xué) RunTime Semantics

            if( yy == xx.getValue() ) …

            X xx; Y yy;

            class Y{

            public:

            Y();  ~Y();  bool operator == (constY& )const;

            };

            class X{

            public:

            X(); ~X(); operator Y()const; //重載轉(zhuǎn)換類(lèi)型操作符 必須成員不能有參數(shù)不能有返回值詳細(xì)在 http://www.shnenglu.com/zqsand/archive/2010/03/15/109748.html里面有介紹

            X getValue();

            };

            看看上面的表達(dá)式怎么執(zhí)行的~~~

            首先等號(hào)運(yùn)算符的參數(shù)確定  if(yy.operator==(xx.getValue()));

            Y的== 需要一個(gè)Y型的參數(shù),但是getvalue得到的是一個(gè)X型的,如果沒(méi)有X到Y(jié)的轉(zhuǎn)型方法,這個(gè)式子是錯(cuò)的~ 而恰好X有個(gè)類(lèi)型轉(zhuǎn)換符~

            if(yy.operator == (xx.getValue().operator Y()))

            增加的代碼都是編譯器默默為我們加上的~~~

            注意在這個(gè)過(guò)程中,我們需要一個(gè)臨時(shí)的Xobject 儲(chǔ)存 getValue返回值 X temp1 = xx.getValue()

            一個(gè)class Y object 儲(chǔ)存 operator Y()返回值 Y temp2 = temp1.operator Y();

            一個(gè) int 放置 等號(hào)返回值  int tmp3 = yy.operator == (temp2);

            最后析構(gòu)函數(shù)會(huì)實(shí)施在每一個(gè)臨時(shí)class object上.

            所以,我們的代碼變成:

            {

            X temp1 = xx.getValue();Y temp2 = temp1.operator Y();int tmp3 = yy.operator == (temp2);

            if(tmp3)  dosth```

            tmp2.Y::~Y();

            tmp1.X::~X();

            }

            surprise~~-----------------------------------------------------------------------

            6.1-對(duì)象的構(gòu)造和析構(gòu)

            ·一般來(lái)說(shuō),dtor會(huì)被放在每一個(gè)離開(kāi)點(diǎn)(object 還存活)之前 ,所以,如果一個(gè)區(qū)段或者函數(shù)有多個(gè)離開(kāi)點(diǎn),那么每一個(gè)return 離開(kāi)點(diǎn)都要插入一個(gè)dtor了。因此我們一般盡量放置object在使用它的程序區(qū)段附近,節(jié)省不必要的對(duì)象產(chǎn)生與摧毀操作。

            ·全局對(duì)象:全局對(duì)象如果有ctor或者dtor的話需要靜態(tài)的初始化操作和內(nèi)存釋放操作。c++中全局對(duì)象放在data segment中,如果不明確指定值,內(nèi)存內(nèi)容為0.

            但是ctor必須等到程序startup后才能實(shí)施。由于必須對(duì)一個(gè)放在datasegment 中的object初始化表達(dá)式evaluate ,所以object需要靜態(tài)初始化

            一種策略(cfont 的 munch)

            為每一個(gè)需要靜態(tài)初始化的檔案產(chǎn)生一個(gè)  _sti()函數(shù),內(nèi)帶必要的ctor調(diào)用操作或者inline expansions。 類(lèi)似的產(chǎn)澀會(huì)給你一個(gè)std()函數(shù)調(diào)用dtor

            一個(gè)_main()函數(shù)調(diào)用sti 一個(gè) exit()函數(shù)調(diào)用_std()

            然后cfont在我們的程序中安插對(duì) _main _exit 的調(diào)用。 最后需要解決的是如何收集各個(gè)對(duì)象的sti和std。cfont使用了nm命令 , 打印出符號(hào)表格(目標(biāo)文件的符號(hào)表),然后munch會(huì)搜索所有用sti或者std開(kāi)頭的目標(biāo)函數(shù),把他們記錄到一個(gè)表格,當(dāng)main和exit調(diào)用時(shí)候便利表格即可。

            修改版本的方法是:system V中,coff格式的目標(biāo)文件,檢驗(yàn)可執(zhí)行文件,找出有著_linknodes并且內(nèi)帶一個(gè)指針指向 sti 和std函數(shù)的文件,把他們都串聯(lián)起來(lái),接下來(lái)把鏈表頭結(jié)點(diǎn)設(shè)置為一個(gè)全局的_head object (定義在新的 patch runtime library),這個(gè)library中有一種不同的_main _exit 他們會(huì)以head為起點(diǎn),遍歷鏈表,調(diào)用sti和std。

            實(shí)際上現(xiàn)在的ELF格式,有init 和.fini兩個(gè)section,完成靜態(tài)初始化和釋放操作。編譯器設(shè)定的startup函數(shù)會(huì)完成平臺(tái)特定的支持

            virtual base class 的指針或者引用存取virtual base class subobject,是一種只有在執(zhí)行期才能加以確定的操作。所以,編譯器需要支持class object 的靜態(tài)初始化,至少涵蓋object的指針和reference。

            局部靜態(tài)對(duì)象

            const Matrix& identity(){

                static Matrix mat_identity;

                return mat_identity;

            }

            mat_identity的ctor必須只執(zhí)行一次,mat_identity的dtor必須只執(zhí)行一次

            編譯器只在identity被調(diào)用的時(shí)候才構(gòu)造mat_identity,這樣避免如果不被調(diào)用也需要構(gòu)造所有對(duì)象。同時(shí)編譯器引入條件式解析~也就是如果構(gòu)造了則解析之

            對(duì)象數(shù)組:

            Points knots[10];

            如果Points沒(méi)有定義ctor和dtor只要分配空間即可

            如果有default ctor ,ctor必須實(shí)施于每個(gè)元素身上~這是由runtime library 完成的。 cfont中 我們使用vec_new()函數(shù)  MS和Sun提供兩個(gè)函數(shù),一個(gè)用來(lái)處理 vbs的class 一個(gè)處理內(nèi)帶base class 的class,后者為 vec_vnew() 函數(shù)原型基本如下

            void* vec_new(void *array,size_t elem_size,int elem_count,void (*ctor)(void*),void(*dtor)(void*,char)))

            array如果是0,數(shù)組由new分配與heap, vec_new(&knots,sizeof(Point),10,&Point::Point,0);

            6.2 new 和 delete 運(yùn)算符

            int *pi  = new int(5);

            執(zhí)行步驟:

            int* pi = __new (sizeof(int));

            *pi = 5;

            int *pi;

            if(pi = __new(sizeof(int)))

               *pi=5;

            delete pi;

            if(pi!=0)

            __delete (pi);

            注意pi并不會(huì)自動(dòng)清除為0!

            CTOR

            Point3d * origin=new Point3d;

            if(origin = __new(sizeof(Point3d))){

            try{

               origin = Point3d::Point3d(origin);   

            }

            calch(…){

            __delete(origin);

            throw;//上傳exception

            }

            }

            DTOR

            delete origin;

            if(origin!=0){

              Point3d::~Point3d(origin);

               __delete(origin);

            }

            一種library對(duì)new的設(shè)計(jì):~~

            extern void* operator new(size_t size){

            if(size==0)size=1;

            void *last_alloc;

            while(!(last_alloc=malloc(size))){

            if(_new_handler) (*_new_handler)();

            else return 0;

            }

            return last_alloc;

            }

            雖然new T[0];是合法的,但是語(yǔ)言要求每次對(duì)new的調(diào)用必須返回一個(gè)獨(dú)一無(wú)二的指針,解決該問(wèn)題的傳統(tǒng)方法是傳回一個(gè)指針,指向默認(rèn)為1byte的內(nèi)存區(qū)塊。所以size被設(shè)為1.然后這種設(shè)計(jì)允許使用者提供一個(gè)屬于自己的_new_handler() 函數(shù)。

            extern void operator delete (void *ptr) { if(ptr)free (char*)ptr;}

            針對(duì)數(shù)組的new 語(yǔ)義:

            int *p_array = new int[5];

            這時(shí)候 vec_new()不會(huì)真正調(diào)用,因?yàn)椋闹饕δ苁前裠efault ctor 實(shí)施于class object數(shù)組的每個(gè)元素身上。new運(yùn)算符會(huì)被調(diào)用:

            int *p_array = (int*) __new(5*sizeof(int));

            如果數(shù)組的class object 有default ctor vec_new才會(huì)被調(diào)用。

            Point3d *p_array = new Point3d[10];編譯成:

            Point3d *p_array = vec_new(0,sizeof(Point3d),10,&point3d::Point3d,&Point3d::~Point3d);

            個(gè)別數(shù)組構(gòu)造如果exception發(fā)生,dtor被傳輸給vec_new ,已經(jīng)構(gòu)造的object需要dtor 實(shí)施。

            delete 時(shí)候,開(kāi)始需要程序員指定大小,后來(lái)編譯器開(kāi)始不適用程序員指定的,而是只需要寫(xiě)delete [] ptr 即可。

            如何記錄數(shù)組大小呢:

            一種方法在vecnew返回的內(nèi)存塊配置一個(gè)額外的word,大小放在其中。

            如果

            class Point {public:virtual ~Point (){}};

            class Point3d : public Point {public:virtual ~Point3d(){}};

            如果Point *ptr = new Point3d[10];

            當(dāng)我們delete [] ptr;時(shí)候只有 Point::~Point被掉用````

            在vc里敲了代碼驗(yàn)證確實(shí)如此~~~

            實(shí)施于數(shù)組上的dtor是根據(jù)交給vec_delete()函數(shù)的被刪除指針類(lèi)型的dtor,也就是point的dtor,每一個(gè)元素大小也被一起傳了過(guò)去。

            如何避免:

            避免一個(gè)base class 指針指向一個(gè)derived class 的數(shù)組。如果真的要這么寫(xiě)看代碼吧

            class point{
            public:
                int p;
                point(){cout<<"point ctor"<<endl;}
                ~point(){cout<<"point dtor"<<endl;}
            };
            class point3d:public point{
            public:
                int q;
                point3d(){cout<<"point3d ctor"<<endl;}
                ~point3d(){cout<<"point3d dtor"<<endl;}
            };
            int main()
            {   
                 point *ptr = new point3d[3];
                 //delete [] ptr; 這樣寫(xiě)是不行的

                 //要這樣寫(xiě)
                 for(int i=0;i<3;i++){
                     point3d * p=&((point3d*)ptr)[i]; //恢復(fù)成point3d數(shù)組指針
                     delete p;
                 }
            }

            Placement Operator New

            有一個(gè)重載過(guò)的new 運(yùn)算符 需要兩個(gè)參數(shù),類(lèi)型為void*

            Point2w *ptw = new(area) Point2w;

            其中area指向內(nèi)存一個(gè)區(qū)塊,用來(lái)放置產(chǎn)生出來(lái)的Point2w object.這個(gè)預(yù)先定義好的placement operator new 實(shí)現(xiàn)方法: 將獲得的指針arena 所指的地址傳回即可

            void* operator new (size_t,void* p) {return p;}

            事實(shí)上,他執(zhí)行的另一半工作是:把point2w 的ctor 實(shí)施于 arena所指的地址上

            Point2w *ptw = (Point2w *)arena; if(ptw!=0)ptw->Point2w::Point2w();

            -------

            p2w->~Point2w;

            p2w = new(arena)Point2w;

            如果我們用

            delete p2w; p2w = new(arena) Point2w;

            delete會(huì)釋放p2w指向的內(nèi)存 由于下一指令還要用到p2w,我們應(yīng)該調(diào)用dtor并保留存儲(chǔ)空間,以便再次使用.

            還有一些關(guān)于placement opeator new 的設(shè)計(jì)問(wèn)題··沒(méi)看明白 不記了··

            6.3臨時(shí)對(duì)象 :

            c++對(duì)臨時(shí)對(duì)象并無(wú)硬性規(guī)定,由編譯器抉擇。

            實(shí)際上 T c = a+ b; T operator + (const T& ,const T&);

            a+b可以直接構(gòu)建于c上

            那么根本不產(chǎn)生臨時(shí)對(duì)象

            但是,意義相當(dāng)?shù)?c=a+b;不能忽略臨時(shí)對(duì)象":

            T temp; temp=operator+(a,b);c.operator =(tmp);tmp.T::~T();

            注意c=a+b;中,直接傳遞c進(jìn)入operator 中,也就是不要tmp的話:由于operator函數(shù)不為其外加參數(shù)調(diào)用dtor(期望一個(gè)新鮮的內(nèi)存),所以必須在其調(diào)用前調(diào)用dtor.然而轉(zhuǎn)換操作會(huì)變成c.T::~T();c.T::T(a+b);copy ctor dtor  copy assignment operator 都可以自定義,所以我們用 析構(gòu)和拷貝構(gòu)造代替賦值一般而言是不安全的,所以需要臨時(shí)對(duì)象調(diào)用operator=

            所以 T c=a+b;比 c=a+b;更有效率

            臨時(shí)對(duì)象生命周期:

            臨時(shí)對(duì)象被摧毀,應(yīng)該是對(duì)完整表達(dá)式求職過(guò)程的最后一個(gè)步驟,該完整表達(dá)式造成臨時(shí)對(duì)象的產(chǎn)生

            如果一個(gè)臨時(shí)對(duì)象綁定在一個(gè)reference上,對(duì)象將殘留,知道被初始化之reference生命結(jié)束,或者知道臨時(shí)對(duì)象的聲明范疇結(jié)束。

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            posted @ 2010-03-19 16:55 rikisand 閱讀(368) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題  下一頁(yè)
            久久黄色视频| 亚洲va久久久噜噜噜久久| 久久人人爽人人人人爽AV| 国产三级久久久精品麻豆三级| 久久久久99精品成人片| 久久综合给久久狠狠97色| 一本久久精品一区二区| 精品一区二区久久| 亚洲AV无码成人网站久久精品大| 国内精品久久久久久久coent| 久久人爽人人爽人人片AV| 思思久久99热只有频精品66| 国产成人精品综合久久久久| 久久国产成人| 亚洲精品国产成人99久久| 精品少妇人妻av无码久久| 久久这里只有精品首页| 亚洲AⅤ优女AV综合久久久| 人人狠狠综合久久亚洲88| 久久久无码精品亚洲日韩蜜臀浪潮 | 欧美亚洲日本久久精品| 青青热久久综合网伊人| 久久99亚洲网美利坚合众国| 97久久婷婷五月综合色d啪蜜芽| 香蕉aa三级久久毛片| 欧美久久亚洲精品| 久久久久久亚洲精品不卡 | 三级三级久久三级久久| 日本欧美国产精品第一页久久| 精品久久久久久无码中文字幕| 亚洲欧美精品伊人久久| 久久这里只有精品久久| 国产叼嘿久久精品久久| 久久国产福利免费| 久久WWW免费人成—看片| 久久精品国产亚洲AV不卡| 精品国产综合区久久久久久| 9191精品国产免费久久| 国内精品久久久久久久涩爱| 亚洲一本综合久久| 国内精品久久久久久不卡影院|