• <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>
            面對現實,超越自己
            逆水行舟,不進則退
            posts - 269,comments - 32,trackbacks - 0
                 摘要: 之所以撰寫這篇文章是因為前段時間花費了很大的精力在已經成熟的代碼上再去處理memory leak問題。寫此的目的是希望我們應該養成良好的編碼習慣,盡可能的避免這樣的問題,因為當你對著一大片的代碼再去處理此類的問題,此時無疑增加了解決的成本和難度。準確的說屬于補救措施了。1. 什么是內存泄漏(memory leak)? 指由于疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。內存泄漏并非...  閱讀全文
            posted @ 2013-05-02 18:29 王海光 閱讀(7167) | 評論 (0)編輯 收藏

            現在流行的進程線程同步互斥的控制機制,其實是由最原始最基本的4種方法實現的。由這4種方法組合優化就有了.Net和Java下靈活多變的,編程簡便的線程進程控制手段。 
              這4種方法具體定義如下 在《操作系統教程》ISBN 7-5053-6193-7 一書中可以找到更加詳細的解釋 
              1、臨界區:通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。 
              2、互斥量:為協調共同對一個共享資源的單獨訪問而設計的。 
              3、信號量:為控制一個具有有限數量用戶資源而設計。 
              4、事 件:用來通知線程有一些事件已發生,從而啟動后繼任務的開始。 
                

            臨界區(Critical Section)


              保證在某一時刻只有一個線程能訪問數據的簡便辦法。在任意時刻只允許一個線程對共享資源進行訪問。如果有多個線程試圖同時訪問臨界區,那么在有一個線程進入后其他所有試圖訪問此臨界區的線程將被掛起,并一直持續到進入臨界區的線程離開。臨界區在被釋放后,其他線程可以繼續搶占,并以此達到用原子方式操作共享資源的目的。 
              臨界區包含兩個操作原語: 
              EnterCriticalSection() 進入臨界區 
              LeaveCriticalSection() 離開臨界區 
              EnterCriticalSection()語句執行后代碼將進入臨界區以后無論發生什么,必須確保與之匹配的LeaveCriticalSection()都能夠被執行到。否則臨界區保護的共享資源將永遠不會被釋放。雖然臨界區同步速度很快,但卻只能用來同步本進程內的線程,而不可用來同步多個進程中的線程。 
              MFC提供了很多功能完備的類,我用MFC實現了臨界區。MFC為臨界區提供有一個CCriticalSection類,使用該類進行線程同步處理是非常簡單的。只需在線程函數中用CCriticalSection類成員函數Lock()和UnLock()標定出被保護代碼片段即可。Lock()后代碼用到的資源自動被視為臨界區內的資源被保護。UnLock后別的線程才能訪問這些資源。 
               

              //CriticalSection 
              CCriticalSection global_CriticalSection; 
               
              // 共享資源 
              char global_Array[256]; 
               
              //初始化共享資源 
              void InitializeArray() 
              { 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=I; 
               } 
              } 
               
              //寫線程 
              UINT Global_ThreadWrite(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               //進入臨界區 
              global_CriticalSection.Lock(); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=W; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               //離開臨界區 
               global_CriticalSection.Unlock(); 
               return 0; 
              } 
               
              //刪除線程 
              UINT Global_ThreadDelete(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               //進入臨界區 
               global_CriticalSection.Lock(); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=D; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               //離開臨界區 
               global_CriticalSection.Unlock(); 
               return 0; 
              } 
               
              //創建線程并啟動線程 
              void CCriticalSectionsDlg::OnBnClickedButtonLock() 
              { 
               //Start the first Thread 
               CWinThread *ptrWrite = AfxBeginThread(Global_ThreadWrite, 
               &m_Write, 
               THREAD_PRIORITY_NORMAL, 
               0, 
               CREATE_SUSPENDED); 
               ptrWrite->ResumeThread(); 
               
               //Start the second Thread 
               CWinThread *ptrDelete = AfxBeginThread(Global_ThreadDelete, 
               &m_Delete, 
               THREAD_PRIORITY_NORMAL, 
               0, 
               CREATE_SUSPENDED); 
               ptrDelete->ResumeThread(); 
              } 
               
              在測試程序中,Lock UnLock兩個按鈕分別實現,在有臨界區保護共享資源的執行狀態,和沒有臨界區保護共享資源的執行狀態。 
             

             

            互斥量(Mutex) 
               
              互斥量跟臨界區很相似,只有擁有互斥對象的線程才具有訪問資源的權限,由于互斥對象只有一個,因此就決定了任何情況下此共享資源都不會同時被多個線程所訪問。當前占據資源的線程在任務處理完后應將擁有的互斥對象交出,以便其他線程在獲得后得以訪問資源。互斥量比臨界區復雜。因為使用互斥不僅僅能夠在同一應用程序不同線程中實現資源的安全共享,而且可以在不同應用程序的線程之間實現對資源的安全共享。 
               
              互斥量包含的幾個操作原語: 
              CreateMutex() 創建一個互斥量 
              OpenMutex() 打開一個互斥量 
              ReleaseMutex() 釋放互斥量 
              WaitForMultipleObjects() 等待互斥量對象 
               
              同樣MFC為互斥量提供有一個CMutex類。使用CMutex類實現互斥量操作非常簡單,但是要特別注意對CMutex的構造函數的調用 
              CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL) 
              不用的參數不能亂填,亂填會出現一些意想不到的運行結果。 
               
              //創建互斥量 

              CMutex global_Mutex(0,0,0); 
               
              // 共享資源 
              char global_Array[256]; 
               
              void InitializeArray() 
              { 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=I; 
               } 
              } 
              UINT Global_ThreadWrite(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               global_Mutex.Lock(); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=W; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               global_Mutex.Unlock(); 
               return 0; 
              } 
               
              UINT Global_ThreadDelete(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               global_Mutex.Lock(); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=D; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               global_Mutex.Unlock(); 
               return 0; 
              } 
              同樣在測試程序中,Lock UnLock兩個按鈕分別實現,在有互斥量保護共享資源的執行狀態,和沒有互斥量保護共享資源的執行狀態。

                

            信號量(Semaphores)


              信號量對象對線程的同步方式與前面幾種方法不同,信號允許多個線程同時使用共享資源,這與操作系統中的PV操作相同。它指出了同時訪問共享資源的線程最大數目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。在用CreateSemaphore()創建信號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設置為最大資源計數,每增加一個線程對共享資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大于0的,就可以發出信號量信號。但是當前可用計數減小到0時則說明當前占用資源的線程數已經達到了所允許的最大數目,不能在允許其他線程的進入,此時的信號量信號將無法發出。線程在處理完共享資源后,應在離開的同時通過ReleaseSemaphore()函數將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大于最大資源計數。 
              PV操作及信號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。信號量S是一個整數,S大于等于零時代表可供并發進程使用的資源實體數,但S小于零時則表示正在等待使用共享資源的進程數。 
              P操作 申請資源: 
               ?。?)S減1; 
                (2)若S減1后仍大于等于零,則進程繼續執行; 
               ?。?)若S減1后小于零,則該進程被阻塞后進入與該信號相對應的隊列中,然后轉入進程調度。 
              V操作 釋放資源: 
               ?。?)S加1; 
               ?。?)若相加結果大于零,則進程繼續執行; 
               ?。?)若相加結果小于等于零,則從該信號的等待隊列中喚醒一個等待進程,然后再返回原進程繼續執行或轉入進程調度。 
               
                信號量包含的幾個操作原語: 
                CreateSemaphore() 創建一個信號量 
                OpenSemaphore() 打開一個信號量 
                ReleaseSemaphore() 釋放信號量 
                WaitForSingleObject() 等待信號量 
               
              //信號量句柄 

              HANDLE global_Semephore; 
               
              // 共享資源 
              char global_Array[256]; 
              void InitializeArray() 
              { 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=I; 
               } 
              } 
              //線程1 
              UINT Global_ThreadOne(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               //等待對共享資源請求被通過 等于 P操作 
              WaitForSingleObject(global_Semephore, INFINITE); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=O; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               //釋放共享資源 等于 V操作 
               ReleaseSemaphore(global_Semephore, 1, NULL); 
               return 0; 
              } 
               
              UINT Global_ThreadTwo(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               WaitForSingleObject(global_Semephore, INFINITE); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=T; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               ReleaseSemaphore(global_Semephore, 1, NULL); 
               return 0; 
              } 
               
              UINT Global_ThreadThree(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               WaitForSingleObject(global_Semephore, INFINITE); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=H; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               ReleaseSemaphore(global_Semephore, 1, NULL); 
               return 0; 
              } 
               
              void CSemaphoreDlg::OnBnClickedButtonOne() 
              { 
               //設置信號量 1 個資源 1同時只可以有一個線程訪問 
               global_Semephore= CreateSemaphore(NULL, 1, 1, NULL); 
               this->StartThread(); 
               // TODO: Add your control notification handler code here 
              } 
               
              void CSemaphoreDlg::OnBnClickedButtonTwo() 
              { 
               //設置信號量 2 個資源 2 同時只可以有兩個線程訪問 
               global_Semephore= CreateSemaphore(NULL, 2, 2, NULL); 
               this->StartThread(); 
               // TODO: Add your control notification handler code here 
              } 
               
              void CSemaphoreDlg::OnBnClickedButtonThree() 
              { 
              //設置信號量 3 個資源 3 同時只可以有三個線程訪問 
               global_Semephore= CreateSemaphore(NULL, 3, 3, NULL); 
               this->StartThread(); 
               // TODO: Add your control notification handler code here 
              } 
              信號量的使用特點使其更適用于對Socket(套接字)程序中線程的同步。例如,網絡上的HTTP服務器要對同一時間內訪問同一頁面的用戶數加以限制,這時可以為每一個用戶對服務器的頁面請求設置一個線程,而頁面則是待保護的共享資源,通過使用信號量對線程的同步作用可以確保在任一時刻無論有多少用戶對某一頁面進行訪問,只有不大于設定的最大用戶數目的線程能夠進行訪問,而其他的訪問企圖則被掛起,只有在有用戶退出對此頁面的訪問后才有可能進入。 
                

             

            事件(Event) 
               
              事件對象也可以通過通知操作的方式來保持線程的同步。并且可以實現不同進程中的線程同步操作。 
              信號量包含的幾個操作原語: 
                CreateEvent() 創建一個信號量 
                OpenEvent() 打開一個事件 
                SetEvent() 回置事件 
                WaitForSingleObject() 等待一個事件 
                WaitForMultipleObjects()         等待多個事件 
                  WaitForMultipleObjects 函數原型: 
                   WaitForMultipleObjects( 
                   IN DWORD nCount, // 等待句柄數 
                   IN CONST HANDLE *lpHandles, //指向句柄數組 
                   IN BOOL bWaitAll, //是否完全等待標志 
                   IN DWORD dwMilliseconds //等待時間 
                   ) 
              參數nCount指定了要等待的內核對象的數目,存放這些內核對象的數組由lpHandles來指向。fWaitAll對指定的這nCount個內核對象的兩種等待方式進行了指定,為TRUE時當所有對象都被通知時函數才會返回,為FALSE則只要其中任何一個得到通知就可以返回。dwMilliseconds在這里的作用與在WaitForSingleObject()中的作用是完全一致的。如果等待超時,函數將返回WAIT_TIMEOUT。 
               
              //事件數組 

              HANDLE global_Events[2]; 
               
              // 共享資源 
              char global_Array[256]; 
               
              void InitializeArray() 
              { 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=I; 
               } 
              } 
               
              UINT Global_ThreadOne(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=O; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               //回置事件 
               SetEvent(global_Events[0]); 
               return 0; 
              } 
               
              UINT Global_ThreadTwo(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=T; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               //回置事件 
               SetEvent(global_Events[1]); 
               return 0; 
              } 
               
              UINT Global_ThreadThree(LPVOID pParam) 
              { 
               CEdit *ptr=(CEdit *)pParam; 
               ptr->SetWindowText(""); 
               //等待兩個事件都被回置 
               WaitForMultipleObjects(2, global_Events, true, INFINITE); 
               for(int i = 0;i<256;i++) 
               { 
               global_Array[i]=H; 
               ptr->SetWindowText(global_Array); 
               Sleep(10); 
               } 
               return 0; 
              } 
              void CEventDlg::OnBnClickedButtonStart() 
              { 
               for (int i = 0; i < 2; i++) 
               { 
               //實例化事件 
               global_Events[i]=CreateEvent(NULL,false,false,NULL); 
               } 
               CWinThread *ptrOne = AfxBeginThread(Global_ThreadOne, 
               &m_One, 
               THREAD_PRIORITY_NORMAL, 
               0, 
               CREATE_SUSPENDED); 
               ptrOne->ResumeThread(); 
               
               //Start the second Thread 
               CWinThread *ptrTwo = AfxBeginThread(Global_ThreadTwo, 
               &m_Two, 
               THREAD_PRIORITY_NORMAL, 
               0, 
               CREATE_SUSPENDED); 
               ptrTwo->ResumeThread(); 
               
               //Start the Third Thread 
               CWinThread *ptrThree = AfxBeginThread(Global_ThreadThree, 
               &m_Three, 
               THREAD_PRIORITY_NORMAL, 
               0, 
               CREATE_SUSPENDED); 
               ptrThree->ResumeThread(); 
               // TODO: Add your control notification handler code here 
              } 
              事件可以實現不同進程中的線程同步操作,并且可以方便的實現多個線程的優先比較等待操作,例如寫多個WaitForSingleObject來代替WaitForMultipleObjects從而使編程更加靈活。 
              

             

            總結: 
              1. 互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越進程使用。所以創建互斥量需要的資源更多,所以如果只為了在進程內部是用的話使用臨界區會帶來速度上的優勢并能夠減少資源占用量。因為互斥量是跨進程的互斥量一旦被創建,就可以通過名字打開它。 
              2. 互斥量(Mutex),信號燈(Semaphore),事件(Event)都可以被跨越進程使用來進行同步數據操作,而其他的對象與數據同步操作無關,但對于進程和線程來講,如果進程和線程在運行狀態則為無信號狀態,在退出后為有信號狀態。所以可以使用WaitForSingleObject來等待進程和線程退出。 
              3. 通過互斥量可以指定資源被獨占的方式使用,但如果有下面一種情況通過互斥量就無法處理,比如現在一位用戶購買了一份三個并發訪問許可的數據庫系統,可以根據用戶購買的訪問許可數量來決定有多少個線程/進程能同時進行數據庫操作,這時候如果利用互斥量就沒有辦法完成這個要求,信號燈對象可以說是一種資源計數器。 

            疑問: 
              在 Linux 上,有兩類信號量。第一類是由 semget/semop/semctl API 定義的信號量的 SVR4(System V Release 4)版本。第二類是由 sem_init/sem_wait/sem_post/interfaces 定義的 POSIX 接口。 它們具有相同的功能,但接口不同。 在2.4.x內核中,信號量數據結構定義為(include/asm/semaphore.h)。 
              但是在Linux中沒有對互斥量的具體提法,只是看到說互斥量是信號量的一種特殊情況,當信號量的最大資源數=1同時可以訪問共享資源的線程數=1 就是互斥量了。臨界區的定義也比較模糊。沒有找到用事件處理線程/進程同步互斥的操作的相關資料。在Linux下用GCC/G++編譯標準C++代碼,信號量的操作幾乎和Windows下VC7的編程一樣,不用改多少就順利移植了,可是互斥量,事件,臨界區的Linux移植沒有成功。 
               
              本文所有事例程序在WindowsXp Sp2 + VC7 下編譯通過。

            本文轉自:http://www.bccn.net/Article/kfyy/vc/jszl/200709/6380_2.html

             

             

            posted @ 2013-04-18 17:06 王海光 閱讀(501) | 評論 (0)編輯 收藏

               解釋以下語句的含義:
                     1
            new A;
                     2
            、new A();    
               也許很多人包括我自己,都可以馬上給出第一種情況的答案:在堆上為A類分配內存,然后調用A的構造函數。這種說法被大家所熟知,因為包括《STL源碼剖析》等大作在內也都是這么寫的(但是你認為這種說法完全正確嗎?
            其實不盡然,答案后面揭曉)
                第二種情況,對象構造的時候初始化列表為空會和第一種有什么不同呢?對于這種在實際工程中很少使用的情況,我一時還真給不出確切的答案。

               網上搜了一下,看到CSDN里面還有專門針對這個問題的一個帖子(原帖鏈接 http://bbs.csdn.net/topics/320161716)。

               好像最終也沒有可以信服的答案,認同度比較高的是這樣的說法:
            加括號調用沒有參數的構造函數,不加括號調用默認構造函數或唯一的構造函數,看需求peakflys注:這種說法是錯誤的,答案后面揭曉)
               既然沒有特別靠譜的答案,不如自己動手找出答案。

               構造以下示例:

            /**
             *\brief example1 difference between new and new()
             *\author peakflys
             *\data 12:10:24 Monday, April 08, 2013
             
            */

            class A
            {
            public:
                int a;
            };

            int main()
            {
                A *pa = new A;
                A *paa = new A();
                return 0;
            }

            查看main函數的匯編代碼(編譯器:gcc (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4) )

            int main()
            {
              4005c4:   55                      push   %rbp
              4005c5:   48 89 e5                mov    %rsp,%rbp
              4005c8:   48 83 ec 10             sub    $0x10,%rsp
                A *pa = new A;
              4005cc:   bf 04 00 00 00          mov    $0x4,%edi
              4005d1:   e8 f2 fe ff ff          callq  4004c8 <_Znwm@plt>         //調用new
              4005d6:   48 89 45 f0             mov    %rax,-0x10(%rbp)           //rax寄存器內容賦給指針pa(rax寄存器里是new調用產生的A對象堆內存地址)
                A *paa = new A();
              4005da:   bf 04 00 00 00          mov    $0x4,%edi
              4005df:   e8 e4 fe ff ff          callq  4004c8 <_Znwm@plt>         //調用new
              4005e4:   48 89 c2                mov    %rax,%rdx                      //rax的內容放入rdx,執行之后,rdx里存放的即是通過new A()產生的內存地址
              4005e7:   c7 02 00 00 00 00       movl   $0x0,(%rdx)                 //把rdx內存指向的內容賦為0值,即把A::a賦值為0
              4005ed:   48 89 45 f8             mov    %rax,-0x8(%rbp)             //rax寄存器內容賦給指針paa(rax寄存器里是new()調用產生的A對象堆內存地址)
                 return 0;
              4005f1:   b8 00 00 00 00          mov    $0x0,%eax
            }
              4005f6:   c9                      leaveq 
              4005f7:   c3                      retq
                通過上面產生的匯編代碼(AT&T匯編不熟悉的可以看注釋)可以很容易看出,new A()的執行,在調用完operator new分配內存后,馬上對新分配內存中的對象使用0值初始化,而new A 僅僅是調用了operator new分配內存!
               是不是這樣就可以下結論 new A()new A多了一步,即初始化對象的步驟呢?

               我們再看看下面這種情況:

            /**
             *\brief example2 difference between new and new()
             *\author peakflys
             *\data 12:23:20 Monday, April 08, 2013
             
            */

            class A
            {
            public:
                A(){a = 10;}
                int a;
            };

            int main()
            {
                A *pa = new A;
                A *paa = new A();
                return 0;
            }

               這種情況是類顯示提供含默認值的構造函數。
               查看匯編實現如下:

            int main()
            {
              4005c4:   55                      push   %rbp
              4005c5:   48 89 e5                mov    %rsp,%rbp
              4005c8:   53                      push   %rbx
              4005c9:   48 83 ec 18             sub    $0x18,%rsp
                A *pa = new A;
              4005cd:   bf 04 00 00 00          mov    $0x4,%edi
              4005d2:   e8 f1 fe ff ff          callq  4004c8 <_Znwm@plt>
              4005d7:   48 89 c3                mov    %rax,%rbx
              4005da:   48 89 d8                mov    %rbx,%rax
              4005dd:   48 89 c7                mov    %rax,%rdi
              4005e0:   e8 2d 00 00 00          callq  400612 <_ZN1AC1Ev>
              4005e5:   48 89 5d e0             mov    %rbx,-0x20(%rbp)
                A *paa = new A();
              4005e9:   bf 04 00 00 00          mov    $0x4,%edi
              4005ee:   e8 d5 fe ff ff          callq  4004c8 <_Znwm@plt>
              4005f3:   48 89 c3                mov    %rax,%rbx
              4005f6:   48 89 d8                mov    %rbx,%rax
              4005f9:   48 89 c7                mov    %rax,%rdi
              4005fc:   e8 11 00 00 00          callq  400612 <_ZN1AC1Ev>
              400601:   48 89 5d e8             mov    %rbx,-0x18(%rbp)
                return 0;
              400605:   b8 00 00 00 00          mov    $0x0,%eax
            }
              40060a:   48 83 c4 18             add    $0x18,%rsp
              40060e:   5b                      pop    %rbx
              40060f:   c9                      leaveq 
              400610:   c3                      retq 

               上面的匯編代碼就不在添加注釋了,因為兩種操作產生的匯編代碼是一樣的,都是先調用operator new分配內存,然后調用構造函數。
               上面的情況在VS2010下驗證是一樣的情況,有興趣的朋友可以自己去看,這里就不再貼出VS2010下的匯編代碼了。

               通過上面的分析,對于
            new A new A() 的區別,我們可以得出下面的結論:
                  
            1、類體含有顯示適合地默認構造函數時,new Anew A()的作用一致,都是首先調用operator new分配內存,然后調用默認構造函數初始化對象。
                 2、類體無顯示構造函數時,new A()首先調用operator new來為對象分配內存,然后使用空值初始化對象成員變量,而new A僅僅是調用operator new分配內存,對象的成員變量是無意義的隨機值!  peakflys注:對于基本數據類型,如int 適用此條)
               注意到,現在很多書籍對new操作符的說明都存在紕漏,例如《STL源碼剖析》中2.2.2節中有以下的描述:


            事實證明,new Foo的操作是否有構造函數的調用是不確定的,具體要看Foo類體里是否有顯示構造函數的出現。

            /*****************************************華麗分割線**************************************
            補充:剛才發現,在C++Primer第四版5.11節中,已經有了對于new A()的說明:

               We indicate that we want to value-initialize the newly allocated object by following the type nameby a pair of empty parentheses. The empty parentheses signal that we want initialization but arenot supplying a specific initial value. In the case of class types (such as string) that define their own constructors, requesting value-initialization is of no consequence: The object is initialized by running the default constructor whether we leave it apparently uninitialized orask for value-initialization. In the case of built-in types or types that do not define any constructors, the difference is significant

                 int *pi = new int;         // pi points to an uninitialized int 

                 int *pi = new int();       // pi points to an int value-initialized to 0 

            In the first case, the int is uninitialized; in the second case, the int is initialized to zero.
               這里給出的解釋和上面自己分析的new A()的行為是一致的。

            /***************************************再次華麗分割線************************************
            鑒于上面的結論是通過GCCVS2010得出的,而且有朋友也提出同樣的質疑,為了確定這種結果是否是編譯器相關的,剛才特意查看了一下C++的標準化文檔。
            摘自:ISO/IEC 14882:2003(E) 5.3.4 - 15
            — If the new-initializer is omitted:
                  — If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized(8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
                  — Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;
            — If the new-initializer is of the form (), the item is value-initialized (8.5);

            所以可以確定,這種情況完全是編譯器無關的(當然那些不完全按照標準實現的編譯器除外)。
            但是通過上面標準化文檔的描述,我們可以看出文中對new A在無顯示構造函數時的總結并不是特別準確,鑒于很多公司都有這道面試題(撇去這些題目的實際考察意義不說),我們有必要再補充一下: 對于new A: 這樣的語句,再調用完operator new分配內存之后,如果A類體內含有POD類型,則POD類型的成員變量處于未定義狀態,如果含有非POD類型則調用該類型的默認構造函數。而 new A()在這些情況下都會初始化。
               PS:估計很多公司的正確答案“ 也不一定正確吧。

             

            本文轉自:http://www.shnenglu.com/peakflys/archive/2013/04/08/199208.html

             

            posted @ 2013-04-18 11:03 王海光 閱讀(467) | 評論 (0)編輯 收藏
            來源于《敏捷軟件開發——原則、模式與實踐》

            常見的設計的臭味——腐化軟件的氣味。

            l         僵化性(Rigidity):很難對系統進行改動,因為每個改動都會迫使許多對系統其他部分的其他改動。

            l         脆弱性(Fragility):對系統的改動會導致系統中和改動的地方在概念上無關的許多地方出現問題。

            l         牢固性(Immobility):很難解開系統的糾結,使之成為一些可在其他系統中重用的組件。

            l         粘滯性(Viscosity):做正確的事情比做錯誤的事情要困難。

            l         不必要的復雜性(Needless Complexity):設計中包含有不具任何直接好處的基礎結構。

            l         不必要的重復(Needless Repetition):設計中包含有重復的結構,而該重復的結構本可以使用單一的抽象進行統一。

            l         晦澀性(Opacity):很難閱讀、理解。沒有很好的表現出意圖。

            敏捷設計是一個過程,不是一個事件。它是一個持續的應用原則、模式以及實踐來改進軟件的結構和可讀性的過程。它致力于保持系統設計在任何時間都盡可能得簡單、干凈以及富有表現力

            敏捷軟件開發宣言:

            我們正在通過親身實踐以及幫助他人實踐,揭示更好的軟件開發方法。通過這項工作,我們認為:
            個體和交互 勝過 過程和工具
            可以工作的軟件 勝過 面面俱到的文檔
            客戶合作 勝過 合同談判
            響應變化 勝過 遵循計劃
            雖然右項也具有價值,但我們認為左項具有更大的價值。
            敏捷開發強調以人為中心,而不是以過程為中心,強調盡可能的溝通(與客戶,與團隊成員),盡可能地以最簡單的設計解決問題(從而能夠擁抱變化)。

            敏捷宣言遵循的原則
            我們遵循以下原則:

             

            1。我們最優先要做的是通過盡早的、持續的交付有價值的軟件來使客戶滿意。

               規劃迭代故事時必須按照優先級安排,為客戶先提供最有價值的功能。通過頻繁迭代能與客戶形成早期的良好合作,及時反饋提高產品質量。敏捷小組關注完成和交 付具有用戶價值的功能,而不是孤立的任務。以前我們都用需求規格說明書或者用例來編寫詳細的需求,敏捷使用用戶故事來羅列需求。用戶故事是一種表示需求的 輕量級技術,它沒有

            固定的形式和強制性的語法。但是有一些固定的形式可以用來參考還是比較有益的。敏捷估算中使用了這個模板:“作為【用戶的類型】,我希 望可以【能力】以便【業務價值】“。使用基于用戶故事的需求分析方法時,仍可能需要原型和編寫文檔,只是工作重點更多的轉移到了口頭交流。

             

            2。即使到了開發的后期,也歡迎改變需求。敏捷過程利用變化來為客戶創造競爭優勢。

              敏捷過程參與者不怕變化,他們認為改變需求是好事情,因為這些改變意味著我們更了解市場需求。
              
            3。經常性的交付可以工作的軟件,交付的間隔可以從幾周到幾個月,交付的時間間隔越短越好。

               迭代是受實踐框限制的,意味著即使放棄一些功能也必須按時結束迭代。只要我們可以保證交付的軟件可以很好的工作,那么交付時間越短,我們和客戶協作就越 緊密,對產品質量就更有益。雖然我們多次迭代,但并不是每次迭代的結果都需要交付給用戶,敏捷開發的目標是讓他們可以交付。這意味著開發小組在每次迭代中 都會增加一些功能,增加的每個功能都是經過編碼、測試,達到了可發布的質量標準的。
              另外敏捷開發項目中對開發階段沒有什么重要的分割,沒有先期的需求階段,然后是分析階段,架構設計階段,編碼測試階段等,在項目真正開始后,每次迭代中都會同時進

            行所有的上述階段工作。
             
            4。在整個項目開發期間,業務人員和開發人員必須天天都在一起工作。

              軟件項目不會依照之前設定的計劃原路執行,中間對業務的理解、軟件的解決方案肯定會存在偏差,所以客戶、需求人員、開發人員以及涉眾之間必須進行有意義的、頻繁 

            的交互,這樣就可以在早期及時的發現并解決問題。
             
            5。圍繞被激勵起來的人個來構建項目。給他們提供所需要的環境和支持,并且信任他們能夠完成工作。

              業務和技術是引起不確定的二個主要方面,人是第三個方面。而業務和技術又必須由人來執行,所以能夠激勵人來解決這些問題是解決不確定性的關鍵。只要個人的目標和團

            隊的目標一致,我們就需要鼓舞起每個人的積極性,以個人為中心構建項目,提供所需的環境、支持與信任。

             

            6。在團隊內部,最具有效果并且富有效率的傳遞信息的方法,就是面對面的交談。

              在十幾或者二十幾個人組成的大團隊中,文檔是一種比較合適的傳遞知識和交流的途徑。而敏捷團隊一般不會很多人(大團隊實施敏捷時也會分成多個小的敏捷團隊),所以

            大量的文檔交流其實并不是很經濟的做法。此時面對面的交談反而更快速有效。
             
            7、可工作的軟件是首要進度度量標準。

               一般的工作都比較容易衡量任務進展,比如讓你去搬運1噸的石頭,我只要去稱一下你已經搬運的石頭重量就知道你完成多少了。而對于軟件來說,在軟件沒有編 碼、測試完

            成之前,我們都不能因為代碼編寫了多少行,測試用例跑了多少個就去度量這個功能是否完成了。衡量這個功能是否完成的首要標準就是這個功能可以工 作了,對用戶來說已經可

            以應用了。

             

            8。敏捷過程提可持續的開發速度。責任人、開發者和用戶應該能夠保持一個長期的、恒定的開發速度。

               很多人都認為軟件開發中加班是很正常的,不加班反而不正常,我對此有點不理解,這個可能是國情所致吧。敏捷過程希望能夠可持續的進行開發,開發速度不會 隨著迭代的任務不同而不同,不欣賞所謂的拼一拼也能完成的態度,開發工作不應該是突擊行為。我們不能指望說突擊這個項目后就可以輕松了,因為完成一個項目 后會接踵而來下一個項目,而只要還是拼拼的態度,下一個項目依舊會讓你的組員再次突擊。這時不知道有人會不會說,那我們就一直加班,也是“持續的開發速 度”啊,這時可要注意了,持續加班智

            慧導致人疲勞、厭倦,保持長期恒定的速度也只是一種理想而已。
             
            9。不斷地關注優秀的技能和好的設計會增強敏捷能力。

              敏捷過程有很多好的技術實踐可以加強產品敏捷能力,很多原則、模式和實踐也可以增強敏捷開發能力。 《敏捷軟件開發-原則、模式與實踐》一書中介紹了很多設計,感興趣的可以去仔細看看。
             
            10。簡單----使未完成的工作最大化的藝術----是根本的。

               我們不可能預期后面需求會如何變化,所以不可能一開始就構建一個完美的架構來適應以后的所有變化。敏捷團隊不會去構建明天的軟件,而把注意力放在如何通 過最簡單的方法完成現在需要解決的問題。這時有人會說,我已經預計到了肯定存在哪些需求擴展點,我們在一開始是否需要考慮呢?這時團隊需要根據自己的理解 去決定是否考慮,如果深信在明天發生了這個問題也可以輕易處理的話,那么就最好先不考慮。
             
            11。最好的構架、需求和設計出自與自組織的團隊。

                    敏捷中有很多種實踐,大家都知道,迭代式開發是主要的實踐方法,而自組織團隊也是主要的實踐之一。在自組織團隊中,管理者不再發號施令,而是讓團隊自身尋找最佳的工作方式來完成工作。要形成一個自組織團隊其實比較難。CSDN采訪Mishkin Berteig中說到 自組織團隊的第一個要素就是必須有一個團隊,而不僅僅是一群人。一群人是一幫在一起工作的人,他們彼此之間并沒有太多的溝通,他們也并不視彼此為一體。項目一開始,我們就會組建“團隊”,但很多時候由構架師、需求人員、開發人員和測試人員組成的是一群人而已。他還認為,團隊的形成必須經歷幾個時期。在 經歷了初期的磨合后,成員才會開始對團隊共同的工作理念與文化形成一個基本的認識和理解。團隊內會逐漸形成規矩,而且這些規矩是不言而喻的。比如,每個人 都知道上午九點來上班,都會主動詢問別人是否需要幫助,也都會去主動和別人探討問題。如果團隊成員之間能夠達成這樣的默契,那么這個團隊將成為一個真正高 效的工作團隊。在這樣團隊中,成員之間相互理解,工作效率非常高。在自組織團隊中,團隊成員不需要遵從別人的詳細指令。他們需要更高層次的指導,這種指 導更像是一個目標,一個致力于開發出更好的軟件的目標??傊?,自組織團隊是一個自動自發、有著共同目標和工作文化的團隊,這樣的團隊總是在向它的組織做出 承諾。但是,實現這些承諾對于自組織團隊來說非常重要。否則,一旦出現問題,團隊成員之間就會出現信任危機。


              雖然敏捷開發小組是以小組為整體 來工作的,但是還是有必要指明一些承擔一定任務的角色。第一個角色是產品所有者(Product Owner)。產品所有者的主要職責包括:確認小組所有成員都在追求一個共同的項目前景,確定功能的優先級以便總是在處理最具有價值的功能,以及作出決定 使得對項目的投入可以產生良好的回報??梢詫獮橐郧伴_發中的“產品經理”。另一角色是開發團隊(developer),這里的開發人員包括了架構師、設計師、程序員、需求人員、測試人員、文檔編寫者等,有時產品所有者也可以被看作是

            開發人員。還有一個重要角色就是項目經理(project manager)。敏捷開發的項目經理會更多的關注領導而不是管理。在某些項目中,項目經理可能同時也是開發人員,少數時候也會擔任產品所有者。
               
            12。每隔一定時間,團隊會在如何才能更有效地工作方面進行反省,然后相應地對自己的行為進行調整。

              由于很多不確定性因素會導致計劃失效,比如項目成員增減、技術應用效果、用戶需求的改變、競爭者對我們的影響等都會讓我們作出不同的反應。 敏捷不是基于預定義的工作方式,而是基于經驗性的方式,對以上這些變化,小組通過不斷的反省調整來保持團隊的敏捷性。

            面向對象設計的原則:

            SRP 單一職責原則
             就一個類而言,應該僅有一個引起它變化的原因。

            l         單一職責原則The Single Responsibility Principle,簡稱SRP):就一個類而言,應該僅有一個引起它變化的原因。在SRP中,我們把職責定義為“變化的原因()”。如果你能夠想到多于一個的動機去改變一個類,那么這個類就具有多于一個的職責。軟件設計真正要做的許多內容,就是發現職責并把那些職責相互分離。事實上,我們將要論述的其余原則都會以這樣或那樣的方式回到這個問題上。

            l         開放封閉原則The Open-Close Principle,簡稱OCP):軟件實體(類、模塊、函數等等)應該是可以擴展的,但是不可以修改的。遵循開放封閉原則設計出的模塊具有兩個主要的特征。它們是:(1)、對于擴展是開放的。這意味著模塊的行為是可以擴展的。當應用的需求改變時,我們可以對模塊進行擴展,使其具有滿足那些改變的新行為。換句話說,我們可以改變模塊的功能。(2)、對模塊行為進行擴展時,不必改動模塊的源代碼或者二進制代碼。模塊的二進制可執行版本,無論是可鏈接的庫、DLL或者Java.jar文件,都無需改動。

            l         Liskov替換原則The Liskov Substitution Principle,簡稱LSP):子類型必須能夠替換掉它們的基類型。OCP原則是OOD中很多說法的核心。LSP是使OCP成為可能的主要原則之一。正式子類型的可替換性才使得使用基類類型的模塊在無需修改的情況下就可以擴展。這種可替換性必須是開發人員可以隱式依賴的東西。

            l         依賴倒置原則The Dependency Inversion Principle,簡稱DIP):(1)、高層模塊不應該依賴于底層模塊。二者都應該依賴于抽象。(2)、抽象不應該依賴于細節。細節應該依賴于抽象。使用傳統的過程化設計所創建出來的依賴關系結構,策略是依賴于細節的。面向對象的程序設計倒置了依賴關系結構,使得細節和策略都依賴于抽象,并且常常是客戶擁有服務接口。事實上,這種依賴關系正式好的面向對象設計的標志所在。

            l         接口隔離原則The Interface Segregation Interface,簡稱ISP):不應該強迫客戶依賴它們不用的方法。如果強迫客戶程序依賴于那些它們不適用的方法,那么這些客戶程序就面臨著由于這些未使用方法的改變所帶來的變更。這就無意中導致了所有客戶程序之間的耦合。我們希望盡可能地避免這種耦合,因此我們希望分離接口。

                  REP 重用發布等價原則
                   重用的粒度就是發布的粒度
                  CCP 共用封閉原則
                  包中的所有類對于同一類性質的變化應該是共同封閉的。一個變化若對一個包產生影響,則將對該包中的所有類產生影響,而對于其他的包不造成任何影響。
                  CRP 共同重用原則
                  一個包中的所有類應該是共同重用的。如果重用了包中的一個類,那么就要重用包中所有類。
                  ADP 無環依賴原則
                  在包的依賴關系圖中不允許存在環。
                  SDP 穩定依賴原則
                  朝著穩定的方向進行依賴。
                  SAP 穩定抽象原則
                  包的抽象程度應該和其穩定程度一致。

            極限編程實踐
            完整團隊
            XP項目的所有參與者(開發人員、業務分析師、測試人員等等)一起工作在一個開放的場所中,他們是同一個團隊的成員。
            計劃游戲
            計劃是持續的,循序漸進的。每2周,開發人員就為下2周估算候選特性的成本,而客戶則根據成本和商務價值來選擇要實現的特性。
            客戶測試
            作為選擇每個所期望的特性的一部分,客戶定義出自動驗收測試來表明該特性可以工作。
            簡單設計
            團隊保持設計恰好和當前的系統功能相匹配,它通過了所有的測試,不包含任何重復,表達出了編寫者想表達的所有東西,并且包含盡可能少的代碼。
            結對編程
            所有的產品軟件都是由兩個程序員,并排坐在一起在同一臺電腦上構建的。
            測試驅動開發
            程序員以非常短的循環周期工作,他們先增加一個失敗的測試,然后使之通過。
            改進設計
            隨時改進糟糕的代碼。保持代碼盡可能的干凈,具有表達力。
            持續集成
            團隊總是使系統完整地被集成。
            集體代碼所有權
            任何結對的程序員都可以在任何時候改進任何代碼。
            編碼標準
            系統中所有的代碼看起來就好像是被單獨一個--非常值得勝任的--人編寫的。
            隱喻
            團隊提出一個程序工作原理的公共景像。
            可持續的速度
            團隊只有持久才有獲勝的希望,他們以能夠長期維持的速度努力工作,他們保存精力,他們把項目看作是馬拉松長袍,而不是全速短跑。

             

            測試驅動開發

            極限編程(eXtreme Programming,簡稱XP)是敏捷方法中最著名的一個。它由一系列簡單卻相互依賴的時間組成。這些實踐結合在一起形成了一個勝于部分結合的整體。其中一個非常重要的,當前也受到格外重視的實踐就是TDD(測試驅動的開發方法)。

            在測試驅動的開發方法中,編寫所有的代碼的目的都是為了使失敗的單元測試能夠通過。首先編寫一個單元測試,由于它要測試的功能還不在,所以它會運行失敗。然后編寫代碼使測試通過。

            編寫測試用例和代碼之間的更迭速度是很快的,基本上幾分鐘左右。測試用例和代碼共同演化,其中測試用例循序漸進地對代碼的編寫進行指導。作為結果,一個非常完整的測試用例集和代碼一起發展起來。

            測試粗略的可以分為單元測試和驗收測試。單元測試是用來驗證系統中個別機制的白盒測試。

            單元測試用來驗證系統的小的組成單元應該按照所期望的方式工作,但是它們沒有驗證系統作為一個整體時工作的正確性。所以,單元測試是必要的,但是不夠充分。

            驗收測試是用來驗證系統滿足客戶需求的黑盒測試。驗收測試由不了解系統內部機制的人編寫。驗收測試是程序,因此是可運行的。通常通過使用專門為應用程序的客戶創建的腳本語言來編寫驗收測試。正如單元測試作為可編譯、運行的有關系統內部結構的文檔那樣,驗收測試是有關系統特性的可編譯、執行的文檔。

            編寫代碼前就編寫單元測試會帶來四個很明顯的好處:

            1、首先編寫測試使得程序中的每一項功能都有測試來驗證它的操作的正確性。這就可以給以后的開發提供支援,使我們可以更自由地對程序進行更改,因為測試可以告訴我們程序仍然具有正確的行為。

            2、首先編寫測試迫使我們必須從程序調用者的有利視角去觀察我們將要編寫的程序。這樣,我們就會在關注程序的功能的同時,直接關注它的接口,我們也就可以設計出便于調用的軟件。

            3、首先編寫測試迫使我們把程序設計為可測試的。為了把程序設計為易于調用和可測試的,程序必須和它周邊環境解耦。這樣首先編寫測試迫使我們解除軟件中的耦合。面向對象設計的原則在進行這種解除耦合方面具有巨大的幫助作用。

            4、首先編寫測試的另一個重要效果是,測試可以作為一種無價的文檔形式。測試就像一套范例,它幫助其他程序員了解如何使用代碼。這份文檔是可編譯、可運行的。它保持最新。它不會撒謊。

            首先編寫驗收測試的行為對于系統的架構方面具有深遠的影響。為了使系統具有可測試性,就必須要在很高的系統架構層面對系統進行解耦合。正如單元測試可以促使你在小的方面可以做出優良的設計決策一樣,驗收測試可以促使你在大的方面做出優良的系統架構決策。

             軟件大師、C++之父Bjarne Stroustrup曾經說過:設計和編程都是人的活動。忘記了這一點,將會失去一切。敏捷軟件開發方法正是認識到軟件開發的這一本質特征而提出的革新性開發方法。使用敏捷開發方法會給我們帶來巨大的好處。當然要完全做到也是很困難的。這不僅需要對敏捷的深刻理解,更需要敏捷團隊成員的共同努力。

            本文參考:http://blog.csdn.net/open2job/article/details/6335000

             

             

            posted @ 2013-04-17 17:13 王海光 閱讀(486) | 評論 (0)編輯 收藏
                 摘要:       最近準備做 Nokia 的 Symbian,Maemo 下觸摸屏開發。考慮到程序的跨平臺可移植性,最終選擇使用 Qt 開發。相對來說,國內關于 Qt 相關文檔并不算很多。作者將 Linux 下編譯并安裝配置 Qt 全過程總結了一下,只希望可以方便更多的朋友!     1、獲得源代碼    ...  閱讀全文
            posted @ 2013-04-08 17:07 王海光 閱讀(8582) | 評論 (0)編輯 收藏
                 摘要: 1、$表示普通用戶,#表示超級用戶(root user)。超級用戶是Linux系統中權限最高的用戶。 2、shell通常以#!起始,例如:#!/bin/bash 3、運行腳本的兩種方式:1、將腳本作為sh的命令行參數。2、將腳本作為具有執行權限的可執行文件。           例如:$ sh scri...  閱讀全文
            posted @ 2013-04-03 16:58 王海光 閱讀(450) | 評論 (0)編輯 收藏
            雖然網絡上很多人使用 Redhat 或者fedora 作為上位機操作系統,但是我覺得使用Ubuntu最為方便,因為需要的軟件包大部分都可以通過 apt-get 方式來安裝,而不必從源代碼開始自己編譯。要知道,自己編譯源代碼可不是一件輕松的事,因為在編譯過程中經常會出現令人意外而且莫名其妙的錯誤。

                我們使用的操作系統是 Ubuntu 8.04,使用目前最新版本的QT 4.4.0,安裝起來即為簡單,只要運行以下命令就行:

            sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig qt4-demos qt4-designer
            sudo apt-get install qtcreator

            注意在這個版本的軟件包中,qt4-dev-tools 包含了Qt AssistantQt Linguist等工具,因此不需要單獨安裝這兩個工具。其它的,qt4-doc 是幫助文檔,包含了Qt中各個類庫的詳細說明以及豐富的例子程序,可以使用Qt Assistant 工具來打開閱讀。qt4-qtconfig 是配置Qt環境的一個對話框,一般默認就行了,很少有必要去更改。qt4-demos 包含很多可以運行起來的可執行文件以及源代碼。qt4-designer是用來設計GUI界面的設計器。


            為了連接MySQL數據庫,需要安裝連接MySQL的驅動程序:

            sudo apt-get install libqt4-sql-mysql

            比起在Windows下安裝和配置QtMySQL驅動來說,簡直太方便了。如果還需要其它的沒有默認安裝的Qt庫,可以在命令行輸入 sudo apt-get install libqt4- 然后按tab鍵自動補全,就會列出所有以libqt4- 開頭的軟件包,如下圖所示:



            這些都可以使用一個命令搞定,而不需要自己從源碼開始編譯。在記不準或不知道名字的情況下,使用tab鍵列出所有可選的軟件包是一個很實用的小技巧。


            在我的項目中,還需要畫一些數據曲線和統計圖表等,而第三方的QWT庫提供了這些功能。同樣,只需要一個命令即可完成安裝:


            sudo apt-get install libqwt5-qt4 libqwt5-qt4-dev


            這時,打開Qt Designer,就會發現左邊的Widget列表里面多了“Qwt Widget”這一組。


            最后,關于集成開發環境我覺得QDevelop很不錯,它跟Qt Designer結合的很好,而且有提示類成員函數的功能。運行以下命令安裝:


             sudo apt-get install qdevelop 


            這樣,使用Qdevelop編寫代碼和編譯、調試,使用Qt Designer設計界面,開發效率較高

            本文轉自:
            http://blog.csdn.net/zhoufanking/article/details/3278790
            posted @ 2013-04-02 14:06 王海光 閱讀(595) | 評論 (0)編輯 收藏

            今天在安裝軟件的時候出現了Package has no installation candidate的問題,如:
            #  apt-get install <packagename>
            Reading package lists... Done
            Building dependency tree... Done
            Package aptitude is not available, but is referred to by another package.
            This may mean that the package is missing, has been obsoleted, or
            is only available from another source
            E: Package <packagename> has no installation candidate
            解決方法如下:
            # apt-get update

            【更新同步安裝列表。在這一步之前可能還需要添加新的源,比如

            vim /etc/apt/sources.list 我添加了2

            deb http://mirrors.163.com/ubuntu/ hardy main universe

            deb http://tw.archive.ubuntu.com/ubuntu/ hardy main universe


            # apt-get upgrade【升級所有可升級的已安裝包?我沒做這一步,也可以】
            # apt-get install <packagename>

            這樣就可以正常使用apt-get了~

            本文轉自:
            http://hi.baidu.com/lozard/item/03b854f5a8630015e2e3bd0a

            posted @ 2013-04-02 13:41 王海光 閱讀(10016) | 評論 (0)編輯 收藏

            安裝SCIM輸入法的步驟


            打開終端,在終端輸入執行以下命令:
            1).終端輸入:sudo apt-get remove scim

            刪除安裝系統的時候裝的那個scim(個人覺得沒什么用,因為一般新安裝是操作系統沒有裝這個)

            2)sudo apt-get install scim

            然后下載安裝scim輸入法。下載完了系統會自己裝上,中間會有提示,直接y就OK了

            3)sudo apt-get install scim-chinese

            這一步是最重要的,這是下載安裝中文輸入法,前面那一步只是下載一個可以運行輸入法的平臺 ,現在是在這個具體平臺上安裝


            中文輸入法

            4) sudo nano /etc/X11/Xsession.d /95xinput

            這個步驟就利用nano新建一個95xinput的文件 ,該文件的具體內容如下:

             /usr/bin/scim -d  
            XMODIFIERS="@im=SCIM"  
            export XMODIFIERS  
            export GTK_IM_MODULE=scim

             

            然后,確定無誤后,保存,按ctrl + o,輸入文件名保存 ,ctrl+x 退出

            5)exit 退出終端

            6)在系統管理中:語言支持的鍵盤輸入方式調整為scim
            7)重新啟動電腦,進入系統通過Crtl+Space切換輸入法

            本文轉自:http://blog.csdn.net/caodesheng110/article/details/7896481

            posted @ 2013-04-02 13:40 王海光 閱讀(453) | 評論 (0)編輯 收藏
            .h文件:
            #include <string>
            using namespace std;

            class ZBase64
            {
            public:
                /*編碼
                DataByte
                    [in]輸入的數據長度,以字節為單位
                
            */
                string Encode(const unsigned char* Data,int DataByte);
                /*解碼
                DataByte
                    [in]輸入的數據長度,以字節為單位
                OutByte
                    [out]輸出的數據長度,以字節為單位,請不要通過返回值計算
                    輸出數據的長度
                
            */
                string Decode(const char* Data,int DataByte,int& OutByte);
            };

            .cpp文件:
            #include "stdAfx.h"
            #include "ZBase64.h"

            string ZBase64::Encode(const unsigned char* Data,int DataByte)
            {
                //編碼表
                const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                //返回值
                string strEncode;
                unsigned char Tmp[4]={0};
                int LineLength=0;
                for(int i=0;i<(int)(DataByte / 3);i++)
                {
                    Tmp[1] = *Data++;
                    Tmp[2] = *Data++;
                    Tmp[3] = *Data++;
                    strEncode+= EncodeTable[Tmp[1] >> 2];
                    strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
                    strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
                    strEncode+= EncodeTable[Tmp[3] & 0x3F];
                    if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;}
                }
                //對剩余數據進行編碼
                int Mod=DataByte % 3;
                if(Mod==1)
                {
                    Tmp[1] = *Data++;
                    strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];
                    strEncode+= "==";
                }
                else if(Mod==2)
                {
                    Tmp[1] = *Data++;
                    Tmp[2] = *Data++;
                    strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
                    strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];
                    strEncode+= "=";
                }
                
                return strEncode;
            }

            string ZBase64::Decode(const char* Data,int DataByte,int& OutByte)
            {
                //解碼表
                const char DecodeTable[] =
                {
            , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            // '+'
            , 0, 0,
            // '/'
            , 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
            , 0, 0, 0, 0, 0, 0,
            , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
            , 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
            , 0, 0, 0, 0, 0,
            , 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
            , 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
                };
                //返回值
                string strDecode;
                int nValue;
                int i= 0;
                while (i < DataByte)
                {
                    if (*Data != '\r' && *Data!='\n')
                    {
                        nValue = DecodeTable[*Data++] << 18;
                        nValue += DecodeTable[*Data++] << 12;
                        strDecode+=(nValue & 0x00FF0000) >> 16;
                        OutByte++;
                        if (*Data != '=')
                        {
                            nValue += DecodeTable[*Data++] << 6;
                            strDecode+=(nValue & 0x0000FF00) >> 8;
                            OutByte++;
                            if (*Data != '=')
                            {
                                nValue += DecodeTable[*Data++];
                                strDecode+=nValue & 0x000000FF;
                                OutByte++;
                            }
                        }
                        i += 4;
                    }
                    else// 回車換行,跳過
                    {
                        Data++;
                        i++;
                    }
                 }
                return strDecode;
            }

            使用示例(結合CxImage庫):
            CString CScanDlg::EncodeImage()
            {//對圖片進行Base64編碼
                ZBase64 zBase;
                //圖片編碼
                CxImage  image;   // 定義一個CxImage對象    
                image.Load(this->m_strImgPath, CXIMAGE_FORMAT_JPG);   //先裝載jpg文件,需要指定文件類型
                long size=0;//得到圖像大小
                BYTE* buffer=0;//存儲圖像數據的緩沖
                image.Encode(buffer,size,CXIMAGE_FORMAT_JPG);//把image對象中的圖像以type類型數據copy到buffer
                string strTmpResult=zBase.Encode(buffer,size);
                CString result;
                result = strTmpResult.c_str();
                return result;
            }

            void CScanDlg::DecodeImageData(CString strData)
            {//對Base64編碼過的數據解碼并顯示原圖片

                ZBase64 zBase;
                int OutByte=0;
                string strTmpResult=zBase.Decode(strData,strData.GetLength(),OutByte);
                int i,len = strTmpResult.length();
                BYTE *buffer = new BYTE[len];
                for (i=0;i<len;++i)
                {
                    buffer[i] = strTmpResult[i];
                }
                CxImage image(buffer,len,CXIMAGE_FORMAT_JPG);//把內存緩沖buffer中的數據構造成Image對象
                delete [] buffer;
                CDC* hdc = m_picture.GetDC();
                m_bitmap = image.MakeBitmap(hdc->m_hDC);
                HBITMAP h0ldBmp = m_picture.SetBitmap(m_bitmap);
                if(h0ldBmp) DeleteObject(h0ldBmp);
                if(hdc->m_hDC) m_picture.ReleaseDC(hdc);
                if(m_bitmap) DeleteObject(m_bitmap);
            }

            本文轉自:http://www.cnblogs.com/phinecos/archive/2008/10/10/1308272.html
            posted @ 2013-03-20 14:00 王海光 閱讀(11332) | 評論 (0)編輯 收藏
            僅列出標題
            共27頁: First 5 6 7 8 9 10 11 12 13 Last 
            久久亚洲中文字幕精品一区四| 久久精品一区二区影院| 久久久亚洲精品蜜桃臀| 国产精品无码久久综合| 久久精品国产久精国产果冻传媒| 国内精品免费久久影院| 久久婷婷成人综合色综合| 伊人久久大香线蕉AV色婷婷色 | 久久久www免费人成精品| 久久一区二区免费播放| 日日狠狠久久偷偷色综合免费| 国产福利电影一区二区三区久久老子无码午夜伦不 | 996久久国产精品线观看| 国产Av激情久久无码天堂| 精品熟女少妇av免费久久| 久久久亚洲欧洲日产国码二区| 久久综合国产乱子伦精品免费| 久久精品中文闷骚内射| AV狠狠色丁香婷婷综合久久| 97久久超碰成人精品网站| 国内精品久久久久久野外| 色综合久久综合网观看| 久久www免费人成看国产片| 人人狠狠综合88综合久久| 欧美日韩精品久久久久| 亚洲国产精品18久久久久久| 久久99精品久久久久婷婷| 国产激情久久久久影院| 伊人久久国产免费观看视频| 少妇久久久久久久久久| 欧美日韩中文字幕久久伊人| 久久久久国产精品嫩草影院| 18禁黄久久久AAA片| 精品久久久久久无码专区不卡| 国产高清美女一级a毛片久久w | 国内高清久久久久久| 久久99国产精品99久久| 人妻少妇精品久久| www.久久99| 久久综合亚洲色HEZYO社区| 久久青草国产精品一区|