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

            cexer

            cexer
            posts - 12, comments - 334, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理
            共4頁: 1 2 3 4 
            re: 將 Timer 對象化[未登錄] cexer 2013-06-25 12:38
            class CTest
            {
            public:
            CTest()
            : m_value( 0x12345678 )
            {
            build_proc();
            }

            public:
            LRESULT CALLBACK member_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
            {
            printf( "hwnd:%d, msg:%d, wparam:%d, lparam:%d\n", (int)hwnd, (int)msg, (int)wparam, (int)lparam );
            printf( "CTest::value: 0x%x\n", m_value );
            return 0;
            }

            void build_proc()
            {
            unsigned char* proc = m_proc;
            ///////////////////////// Prolog.
            __CODE( 1, ( 0x55 ) ); // 55 push ebp
            __CODE( 2, ( 0x8B, 0xEC ) ); // 8B EC mov ebp,esp
            __CODE( 6, ( 0x81, 0xEC, 0xC0, 0x00, 0x00, 0x00 ) ); // 81 EC C0 00 00 00 sub esp,0C0h
            __CODE( 1, ( 0x53 ) ); // 53 push ebx
            __CODE( 1, ( 0x56 ) ); // 56 push esi
            __CODE( 1, ( 0x57 ) ); // 57 push edi
            __CODE( 6, ( 0x8D, 0xBD, 0x40, 0xFF, 0xFF, 0xFF ) ); // 8D BD 40 FF FF FF lea edi,[ebp+FFFFFF40h]
            __CODE( 5, ( 0xB9, 0x30, 0x00, 0x00, 0x00 ) ); // B9 30 00 00 00 mov ecx,30h
            __CODE( 5, ( 0xB8, 0xCC, 0xCC, 0xCC, 0xCC ) ); // B8 CC CC CC CC mov eax,0CCCCCCCCh
            __CODE( 2, ( 0xF3, 0xAB ) ); // F3 AB rep stos dword ptr es:[edi]

            ////////////////////// Codes
            __CODE( 3, ( 0x8B, 0x45, 0x14 ) ); // 8B 45 14 mov eax,dword ptr [ebp+14h] [lparam]
            __CODE( 1, ( 0x50 ) ); // 50 push eax
            __CODE( 3, ( 0x8B, 0x45, 0x10 ) ); // 8B 45 10 mov eax,dword ptr [ebp+10h] [wparam]
            __CODE( 1, ( 0x50 ) ); // 50 push eax
            __CODE( 3, ( 0x8B, 0x55, 0x0C ) ); // 8B 55 0C mov edx,dword ptr [ebp+0Ch] [msg]
            __CODE( 1, ( 0x52 ) ); // 52 push edx
            __CODE( 3, ( 0x8B, 0x45, 0x08 ) ); // 8B 45 08 mov eax,dword ptr [ebp+8] [hwnd]
            __CODE( 1, ( 0x50 ) ); // 50 push eax
            __CODE( 1, ( 0xB9 ) ); __PTR( this ); // B9 ?? ?? ?? ?? mov ecx, this
            __CODE( 1, ( 0x51 ) ); // 51 push ecx
            __CALL( &CTest::member_proc ); // E8 ?? ?? ?? ?? call CTest::member_proc

            /////////////////////// Epilog.
            __CODE( 1, ( 0x5F ) ); // 5F pop edi
            __CODE( 1, ( 0x5E ) ); // 5E pop esi
            __CODE( 1, ( 0x5B ) ); // 5B pop ebx
            __CODE( 6, ( 0x81, 0xC4, 0xC0, 0x00, 0x00, 0x00 ) ); // 81 C4 C0 00 00 00 add esp,0C0h
            __CODE( 2, ( 0x8B, 0xE5 ) ); // 8B E5 mov esp,ebp
            __CODE( 1, ( 0x5D ) ); // 5D pop ebp
            __CODE( 3, ( 0xC2, 0x10, 0x00 ) ); // C2 10 00 ret 10h

            DWORD old = 0;
            VirtualProtect( &m_proc, sizeof(m_proc), PAGE_EXECUTE_READWRITE, &old );
            }

            WNDPROC get_proc()
            {
            return (WNDPROC)(void*)m_proc;
            }

            public:
            char m_proc[1024];
            int m_value;
            };


            int main( int argc, char** argv )
            {
            CTest test;
            WNDPROC proc = test.get_proc();
            proc( (HWND)1, 2, 3, 4 );

            return 0;
            }
            re: 將 Timer 對象化[未登錄] cexer 2013-06-25 12:37
            #include <iostream>
            #include <string>
            #include <windows.h>
            #include <cstdio>
            using namespace std;


            template<class T, class S>
            inline T union_cast( S s )
            {
            union
            {
            T t;
            S s;
            } u;
            u.s = s;
            return u.t;
            }

            #define __CODE1( a ) \
            *(proc++) = a

            #define __CODE2( a1, a2 ) \
            *(proc++) = a1; \
            *(proc++) = a2

            #define __CODE3( a1, a2, a3 ) \
            *(proc++) = a1; \
            *(proc++) = a2; \
            *(proc++) = a3

            #define __CODE4( a1, a2, a3, a4 ) \
            *(proc++) = a1; \
            *(proc++) = a2; \
            *(proc++) = a3; \
            *(proc++) = a4

            #define __CODE5( a1, a2, a3, a4, a5 ) \
            *(proc++) = a1; \
            *(proc++) = a2; \
            *(proc++) = a3; \
            *(proc++) = a4; \
            *(proc++) = a5

            #define __CODE6( a1, a2, a3, a4, a5, a6 ) \
            *(proc++) = a1; \
            *(proc++) = a2; \
            *(proc++) = a3; \
            *(proc++) = a4; \
            *(proc++) = a5; \
            *(proc++) = a6

            #define __CODE( n, a ) __CODE##n a

            #define __PTR( p ) \
            { \
            *( (void**)proc ) = union_cast<void*>(p);\
            proc += sizeof(void*); \
            }

            #define __CALL( p ) \
            { \
            *(proc++) = 0xE8; \
            unsigned char* pfunc = union_cast<unsigned char*>(p);\
            *( (ptrdiff_t*)proc ) = pfunc - proc - 4; \
            proc += 4; \
            }
            re: 將 Timer 對象化[未登錄] cexer 2013-06-25 12:35
            其實可以徹底擺脫那個static,辦法就是在直接(或者使用JITAssembler)手動生成static的代碼,跟thunk替換棧上數據一樣的道理。只是這樣生成的代碼同時與編譯器和CPU綁定了,與編譯器綁定是因為各個編譯器生成的調用成員函數的方式可能不一樣。
            Android上有很多現成的HTTP服務端應用,另外busybox自帶httpd。不過樓主嘗試一下也不是壞事。
            一樓的同志,好!果然是江湖中人,夠爽快!
            二樓的同事,人家也沒說是賺錢的啊,咋就得了個”在錯誤的道路上越走越遠“的結論呢。
            我看挺好的!
            我覺得boost::pool的ordered_malloc和ordered_free函數是有必要的,它們是作為ordered pool的接口部分而存在的,使用場景不一樣,和malloc和free是沒有可比性。

            boost::pool中有一個函數malloc_n用來申請幾塊連續的partition。一個block是以partition為粒度劃分,以單向鏈表鏈接起來,多次malloc/free的動作之后,這些partition在鏈表中的邏輯順序和它們在內存中的實際順序極有可能是不一致的,此時要得到連續的partition,必須要遍歷鏈表,找出在內存中實際連續的partition,并將它們在鏈表中的順序也重新以連續的順序鏈接,然后返回給調用者。

            如果將鏈表的順序與內存中實際順序的不一致程度叫做它的無序度,顯然這個遍歷操作的耗費的時間,和鏈表的無序度是成正比的。如果這種malloc_n的操作很頻繁,那么這種遍歷鏈表重新鏈接的操作會很費時。

            這種頻繁申請多個連續partition的場景下正是使用ordered pool的地方,正如pool作者在代碼寫的注釋那樣:
            // Note: if you're allocating/deallocating n a lot, you should
            // be using an ordered pool.

            ordered pool內部的所有partition鏈表無序度為0,即所有partition在內存中的實際順序和它們在鏈表中的邏輯順序完全一致,對于malloc_n這樣的請求,可以更快滿足。也因此boost::pool提供了ordered版本的操作接口,這組接口保證每次free之后鏈表的順序不會亂。

            不過,我個人覺得block以partition為粒度劃分是沒必要的,可以在收到請求的時候按實際需求劃分,盡力使整個塊保持連續,可以極大地避免產生碎片,降低ordered_malloc的ordered_free的時間。

            當然ordered_xxx函數不應該和其它的函數混用,否則就是陪了夫人又折兵的買賣,即浪費了ordered_xxx的時間,又無法得到更快malloc_n的好處。
            當使用CreateProcess傳入命令行參數的時候,argv[0]可以是任何值,不一定是程序路徑或程序名。
            搞笑啊,樓上你冒用ID很光彩?看來被人罵傻逼沒罵錯
            那些出口就罵人的,都是些畜牲嗎?你爹媽沒教過你怎么說人話?
            樓主你的文章質量都不錯,就是有點偏離群眾口味。
            嵌入式?如果是一般應用開發面試出這種題有點不靠譜,寫產品的人哪能鉆到這樣的細節里去。
            @三夏健
            說得有道理,并且我補充你一下,“紙上得來終覺淺,絕知此事要躬行”,這句話不能太單純地理解。首先第一步要“紙上得來”,如果自己的理解已經超越了紙面上能給你的,然后就再“躬行”。理論基礎要扎實,實踐才能有的放矢。另外有些東西是知識結構的基本結點,比如說“1+1=2”,本來就是“淺”的,沒必要“躬行”。
            re: C++雜談[未登錄] cexer 2011-07-14 20:45
            應用的框架到了比較高的階段,所面臨的問題的寬度和深度已經完全超越了語言之間的微妙界線,所以像 shared_ptr 這類語言底層的東西,不能拿到這種場合來說。boost 是個大雜噲,有些東西用起來很不錯,比如說 shared_ptr,有些東西不是拿來用的,是實驗室產物,像你說的 tuple 確實是不大實用。
            上面有人竟然拿 auto_ptr 來說多 CPU 并發。這種問題就好像,你在路上撿到一塊鼠標墊,然后就開始發愁,還配點啥才能玩上魔獸世界。
            re: c++處女類[未登錄] cexer 2011-07-14 20:30
            大哥,C++是語言的藝術,講究說學逗唱,你直接擺代碼是怎么個回事啊。
            這跟在沒在首頁可沒關系。我是說解決問題的方式,像導出符號這種按步就搬的套路,自己去猜,從學習成長的角度來說,不如系統地找本書看看來得有效率。雖然自己試,長久下來也能積累知識,只是學習到了一個階段就會有瓶頸,需要把零散知識融匯貫通的時候就不如那么隨心所欲了,會有那種怎么也打不通仁督二脈的感覺。另外,我是以為以為樓主寫了一個類似 dll2lib 的工具,就點進來的,有點上當的感覺啊。
            知識結構得系統,完整,別自己東弄一點西猜一點,零零散散散的,自己不懂就找個教程找本書從頭至尾好好看看,要不出了問題都不知道在哪里.
            不管是不是牛人,與人討論的時候,都不要擺出“蹉,來食”的施舍姿態。作為做技術的,術業有專攻,沒有誰是十項全能宇宙無敵的,所以不要輕易否定別人的成果。作為做人的基本原則,行前三思言必三省,考慮一下自己的言行是否會破壞別人的心情。

            模式匹配我了解的不多,不過詞法分析正則表達式有窮自動機什么的,是成熟很多年的技術了,只是能沉下心來啃書寫代碼的人不多,能有自己思考的人更少,因此我很佩服樓主的編譯器功底。《代碼之美》看過,與想像中的有差距,比較雞肋的一本書,樓主所說的代碼剛好也看過,飯同學的代碼確實不如它精巧,但是貴在原創,我能夠體會他的成就感被人擊破時的氣憤。

            既然飯同學說你態度有問題,你就有則改之,無則加勉好了。如果有一個人說你有問題,你可以不必太在意。如果有兩個人說你有問題,你就要想想到底是誰的問題了。如果有三個人說你有問題,那就是你一定有問題了。


            不錯的文章,樓主是個低調做事的人,支持!
            我拜托把這難看的界面改改,回復功能增強一點。
            實現一個functor,除了眾所周知的功能,我建議樓主再考慮以下這兩點:

            1 給返回void(無返回值)的functor綁定一個有返回值的可調用體,這個貌似boost::function是支持的。這功能是需要的,因為實際上很多時候,我們的functor不關心返回值,就好像某個消息無論你返回什么系統都執行相同的操作,這種情況下,如果綁定的可調用體返回了什么值,functor應該檢測到并使用某種屏蔽手段,而不是報錯“對不起,返回類似不匹配”。

            2 給返回非void(有返回值)的functor綁定一個返回void(無返回值)的可調用體,這個貌似boost::function不支持。這功能是需要的,因為有時候functor需要一個明確的返回值,就像WM_ERASEBKGND消息,根據返回TRUE或FALSE的不同,系統會決定是否自己來畫窗口背景。如果可調用體返回void(無返回值),那么functor應該檢測到它,并在返回時提供一個默認的返回值,而不是在綁定時就報錯“對不起,返回類似不匹配”。

            以上兩點都可以通過模板元編程實現,通過typetraits檢測返回值,并根據functor和可調用體之兩者返回值的不同組合,來選擇不同的返回策略。

            另外還有,如果想綁定系統函數如Windows API,或者其它第三方提供的函數,你還需要考慮調用約定的問題,因為 __stdcall,__cdecl,__fastcall的不同,都會使函數簽名不同。有多少種調用約定,functor的綁定函數的數量就需要乘以多少,這是個體力活,可以用預處理元和文件包含來減少體力消耗。
            @飛舞的煙灰缸
            【function的多播實現還是有點麻煩。
            += 倒是簡單,但是要實現 -=這樣的操作就需要判斷function相等,麻煩就比較大了】

            我想你指的麻煩,可能是你想實現這樣的功能:
            // 加入
            on_event += message_handler( handler );
            // 刪除
            on_event -= message_handler( handler );

            // 加入
            on_event += message_handler ( &Window::handle_resized,this );
            // 刪除
            on_event -= message_handler ( &Window::handle_resized,this );

            這樣的方式實現其實也不難,但是絕對需要 RTTI 那種東西的支持,另外還有一個問題就是這樣的方式使用用起來太麻煩,比如:

            // 加入
            on_event += message_handler ( &Window::handle_resized,this );
            // 刪除
            on_event -= message_handler ( &Window::handle_resized,this );

            如果庫提供了類似 boost::asio 那種參數綁定的功能,看看有多麻煩:
            // 加入
            on_event += message_handler ( &Window::handle_resized,this,Argument::size,Argument::caption );
            // 刪除
            on_event -= message_handler ( &Window::handle_resized,this,Argument::size,Argument::caption );


            其實這個功能有比你個簡單得多的實現方式,給一個 handler 綁定一個名字,到時刪除這個名字即可,見下例:
            // 加入
            on_event += message_handler ( name,handler );
            // 刪除
            on_event -= message_handler( name );


            @OwnWaterloo
            【借寶地請教一下~ 對于handler, 是否需要如此的動態?
            A. 完全動態
            B. 完全靜態
            C. 兩者結合, 動態部分自己實現。
            如上, 需要A那種靈活性么? 缺之不可?
            因為我自己確實沒寫過幾個gui程序, "作為一個庫的用戶", 沒有足夠的這方面的使用經驗。】


            說說我的看法:A并不是必須的,比如說MFC,可以算是完全靜態的,其所有的消息映射代碼都是用宏堆死的選擇語句,提供的動態功能基本上無,優勢很明顯,一個類的所有實例共享一份映射數據,具有空間優勢。但是一個獨立的對象不能有它自己處理事件的方式,這明顯不是面向對象的封裝方式,運行時靈活性大打折扣,這樣說起來很模糊,仍然舉例MFC來說明:

            比如說使用MFC運行時創建的一個按鈕,怎么樣才能把這個按鈕的消息加到消息映射里去呢?對不起,不能。因為按鈕ID是動態生成的,那些映射宏什么的到運行時都成了浮云。解決辦法當然也有:回到原始時代--要么在父窗口的消息回調函數里檢查WM_COMMAND和BN_CLICK,二是任勞任怨地去自己重寫一個按鈕類,并在自己的消息回調里響應WM_COMMAND的反射消息并檢測BN_CLICK,然后進行處理--看看有多麻煩。

            所以我覺得一個好的庫,應該能夠同時提供兩者,就是你說的C。同時支持靜態和動態的映射方式,關鍵是庫要實現得好,在沒有使用動態映射的時候,這個動態映射的功能就好像不存在一樣,這樣大多數時候既能夠享受空間優勢,在需要的時候又能發揮它的動態優勢。免得用戶要在在空間優勢和靈活性之間做出痛苦的選擇。
            不說MFC那種陳舊的消息機制,用boost::function,boost::bind,boost::signal之類的來實現消息機制,也算有點out了,而且這種實現已經有框架使用(比如SmartWin++),不再具有新意了,其實強大的C++可以完成遠比它們更高級的功能,列舉三點:

            1 框架可以給同一個消息源添加任意多個個完全不同的消息處理器,類似函數重載,可以將這個功能命名為處理器重載。僅僅是類似boost:function和boost:signal那種固定簽名的工具,是無法完成這樣的功能的,如下所示:

            // 自由函數
            void global_handler(){}

            // 一段腳本
            Script script_handler = create_script( /*這是一段腳本*/ );

            // 系統函數
            int WINAPI MessageBox( HWND,LPCTSTR,LPCTSTR,UINT );

            // 具有不同參數的成員函數
            viod Class:memeber_handler_void(){}
            void Class::member_handler_size( Size size ){}
            void Class::member_handler_int( int x,int y ){}

            // 消息映射
            Window window;
            Class object;
            window.on_resized += message_handler( global_handler );
            window.on_resized += message_handler( script_handler );
            window.on_resized += message_handler( &Class::member_handler_void,&object );
            window.on_resized += message_handler( &Class::member_handler_size,&object );
            window.on_resized += message_handler( &Class::member_handler_int ,&object );
            window.on_resized += message_handler( &::MessageBox,NULL,"Hello World",MB_OK );


            2 框架能夠進行返回值檢查(眾所周知的,在windows消息系統中,很多消息需要進行特殊的返回值檢查,強WM_ERASEBKGND之類的),比如一個closing消息,如果處理器返回非void類型,并且能夠強制轉換為true,則表明它同意關閉窗口,如果能夠強制轉換為false,則表示它阻止框架進行關閉,如果處理器返回值類型是void,則表示它不關心關閉與否,讓框架進行默認處理。這個功能可以命名為返回值智能檢測。如下所示:

            // 這個處理器不關心窗口是否要關閉
            void handle_closing_dont_care( Window* window )
            {
            }

            // 這個處理器告訴框架不要關閉
            LRESULT handle_closing_no()
            {
            return 0;
            }

            // 這個處理器告訴框架進行關閉
            bool handle_closing_yes()
            {
            return true;
            }

            // 消息映射,窗口最終是否關閉取決于最后一個處理器的決定。
            Window window
            window.on_closing += message_handler( handle_closing_dont_care );
            window.on_closing += message_handler( handle_closing_no );
            window.on_closing += message_handler( handle_closing_yes );


            3 框架提供消息分解者,允許使用者自己組合自己的處理器參數,類似boost::asio的handler綁定bytes_transfered和error_code的方式,可以把這個功能命名為消息參數任意組合,比如同一個消息resized,有的處理器需要當前窗口的大小,有的處理器需要當前窗口的標題,有的處理器同時需要兩者,則消息映射時手動組合消息分解者即可。更進一步,對于某些預注冊的簽名,框架可以智能提供分解者,免去使用者手動提供的麻煩,例如簽名 (Window*,Size) 已經預先注冊,則具有這個簽名的處理器不用手動指定消息分解器
            示例代碼如下:

            // 這個處理器需要當前窗口大小
            void handle_resized_size( Size size ){}

            // 這個處理器需要窗口標題
            void handle_resized_text( String caption ){}

            // 這個處理器都需要
            void handle_resized_both( Size size,String caption )


            // 消息映射的時候,同時指示自己需要什么參數
            Window window
            window.on_resized += message_handler( handle_resized_size,Window::Argument::size )
            window.on_resized += message_handler( handle_resized_text,Window::Argument::text )
            window.on_resized += message_handler( handle_resized_both,Window::Argument::size,Window::Argument::text )


            void handle_resized( Window* window,Size size ){}
            window.on_resized += message_handler( handle_resized );

            4 但是。。。。。在C++.0x.lamda的面前,以上一切都成了浮云。把lamda作為消息處理器,它自身就同時提供了以上1,2,3的所有優點,簡潔優雅使用方便,物美價廉童叟無欺,以上例說明:

            // 這個處理器需要當前窗口大小
            window.on_resized += []( Size size ){
            }( window::Argument::size );

            // 這個處理器需要窗口標題
            window.on_resized += []( String caption ){
            }( Window::Argument::text );

            // 這個處理器都需要
            window.on_resized += []( Size size,String caption ){
            }( window::Argument::size,Window::Argument::text );

            我正在寫的就是這么一個框架,上面列舉的消息機制都完成了,正在進行博主所指第4步封裝控件和第5步(寫文檔,作為一個目標是開源的框架,是最重要的步驟),目前代碼已經有兩萬多行,消息機制的其實占很少部分,大多代碼是控件的封裝。

            re: 軟件開源很重要嗎? cexer 2010-09-21 22:24
            我覺得軟件開源沒有合不合適和值不值得,只有愿不愿意。同時,不管開源如何地重要,開源與否都只是一種權利,不是義務,除非誰寫的代碼已經牛到了使人類科技跳躍發展二十年的程度,他不開源人類就要被外星人消滅。

            但是真正要問一下,軟件開源重要嗎?我想沒人會給出否定的答案。如果沒有開源這東西,很難想像如今的軟件行業還在哪個歷史階段以蝸速前進。所以作為程序員,在保證自己利益的前提下進行開源,于人于已都是最好的。蜘蛛俠里有句話:“有多大的能力,就承擔多大的責任”。

            話又說回來,那些不能滿足自己欲望就攻擊別人的人,有不如人的,有得不到的,就吐口水翻白眼罵臟話的人,和低等級動物沒有區別。對于這類缺乏基本教養的動物,它叫得越厲害越反而不要給它,就讓它在那里出丑。要不然你給它了它會嫌你的東西不好,罵得更厲害。

            網絡是個大黑屋,沒有道德和法律的探照燈,反而可以顯出人和人的區別。按理說技術社區既沒有政治立場的對立,也沒有經濟利益的沖突,純粹的技術交流應該是很愉快的,去過一些國外的技術社區也基本上氣氛就是這樣單純。但是神奇的中國,就連技術社區都那么地不和諧,所以說垃圾已經塞滿中國社會各個角落。

            @陳梓瀚(vczh)
            我對這個主題相關的技術不感興趣。之所以留言,是覺得這篇日志的標題不妥,標題說“如何設計世界上最好的”,內容里卻只“舉出一些需要注意的地方”,既沒見“設計”,更不知“如何”,幾張圖倒是占了大部分的篇幅,這樣的話,“我寫過的一個代碼行統計工具”是個更適合的標題。
            沒有看到你對題目中《如何....》的解答,只看到提出問題,沒有看到提供解決方案。
            re: &quot;Inception&quot; 簡評 cexer 2010-09-06 10:14
            確實好電影,好久沒看過這么好看的電影了。不過呢,還是有些不足,雪地槍戰戲雖然有了架子,可是節奏單調沒有高潮,失重狀態的打斗也沒有打擊感,隔靴騷癢一樣,我覺得這兩個地方可以更精彩。配樂單薄,電影過后完全沒有配樂的回味,應該找 Hans Zimmer 來配樂(竟然還真是他配的)。

            很喜歡電影的結尾。最后從最底層夢中醒來的過程,導演故意處理沒有過渡,直接簡單得讓人難以相信。醒來后的一切又是那么朦朧,周圍人的眼神,兩個孩子的穿著和動作,留給觀眾一個大懸念:陀螺到底會不會停下來?
            很多人先有罵人的欲望,再找罵人的理由,所謂欲罵之人,何患無罪,跟幾流學校什么的無關。樓主不必和這類人一般見識,有一句話說得好,不要和SB講道理,因為他會把你的智商拉到和他同一水平,然后以多年的SB經驗打敗你。

            最近老聽說起造輪子。看看開發技術的發展史,只有造輪子才是技術發展的唯一道路。只是中國造輪子的人雖多,可是造大輪子的人太少,小打小鬧的功能類太多,能大規模復用的框架太少。至于那些批判造輪子的人,忍受了東拼西湊,偷這抄那的道德譴責,忍受了接口參差,代碼混亂的身心煎熬,最終能夠完成項目,雖然也是一種勇氣,但不知道他們批判別人的優越感來自哪里。

            關于首頁原創創精華。CPPBLOG是一個不知進取的博客園,n年了界面和功能從未有一點的進步,界面難看不說了,作為一個技術社區,連首頁推薦模塊都沒有,回復功能之弱讓vckbase驚嘆,使CSDN側目,所謂首頁的原創精華,有無私的分享,也有自大的炫耀,有原創的思考,也有盲目的轉載,隨便什么人寫了兩行腳本,完成了一個家庭作業,都可以放到首頁原創精華區去,整個博客園無管理無組織,也讓人沒有寫東西的欲望。

            @白云哥

            [[[[“Because vectors keep an array format, erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions”

            “This invalidates all iterator and references to elements after position or first.”

            刪除對象后會讓迭代器之后的對象移動,因此而導致迭代器失效


            map的實現,紅黑樹,在插入和刪除對象后因為要做平衡,所以同樣也有可能導致迭代器的失效]]]]

            就這兩條原因,不會使迭代器失效,我所說的迭代器失效,是指容納它數據結構的內存不存在。對于連續內存的容器,刪除進行元素移位,迭代器的內存還在,對于非連續內存的操作,map,list,set之類的都鏈式的實現,這類的結點銷毀的應該只是鏈當前結點,對其它結點的只有修改,所以不應該失效。至于2010為什么失效,有點好奇,刪除操作也要內存重分配,我覺得這是不好的實現。
            可以結合兩種方法。刪除用標記緩存刪除的方法,添加用緩存延遲添加的方法好。
            @白云哥
            呵呵,學習了,看來還是你的辦法穩當。這確實是標準庫的實現相關的,我上面說的也都是基于估計它的一般實現,很好奇2010的vector是怎么樣實現的,會出現這種失效的問題。
            @白云哥
            你看到只刪除了一半,是因為對于vector這種容器,移除前面元素,后面的元素會整體往移一位,本來指向下一個元素的迭代器指向了下下個元素,后面的循環會漏掉下一個元素,這個我在上面也說過的。對于list,set,map之類的就能完全刪除。需要從中間刪除的容器,最好不要用vector,元素移位的操作不是常數時間的。
            @白云哥
            容器循環中的操作有四種,循環中查詢,循環中更改,循環中刪除,循環中添加,這些操作都圍繞迭代器進行的。
            循環中查詢,循環中更改(這兩類操作其實也包含了循環中循環,循環中的循環中的循環,循環中的循環中的循環中的循環。。。)因為不會改變迭代器的合法性,不會有什么問題。

            循環中添加和刪除則不一樣,循環中添加有可能導致所有元素內存重分配,導致所有迭代器失效,而刪除操作一般來說不會產生內存重分配的情況,目前std內的容器應該都是如此(七分分析三分猜測,正確性八九不離十)。

            所以循環中刪除只會使當前刪除操作的迭代器失效,使得不能更新之使其指向下一個元素,而不會影其它迭代器。如list這類的容器,所有元素內存都是單獨分配的,針對添加操作進行一次單獨的內存分配,不會影響到現在有迭代器的合法性 ,但有可能刪除操作導致元素重排,元素移位,使得循環不完全,漏掉元素。

            循環中添加如果導致內存重分配,則會使所有現有的迭代器失效,例如vector,string這類容器要保證其內存是連續的,添加時內存有可能會重分配,導致以前的迭代器全部失效。

            所以針對循環中添加和刪除的幾種解決方法分析如下:
            在循環中保存下一個迭代器的方法:對于刪除操作是沒有任何問題的(關于你說的“刪除容器對象有可能使得之前所保存的迭代器全都失效”,目前std內的容器應該都不會發生這種情況),但對于添加操作,則只適用于非連續內存的容器如list,不適用于連續內存的容器如vector。這個辦法優點是沒有時間空間的成本,缺點是對于添加操作,有些容器不支持。

            使用緩存進行延遲操作的方法:對于刪除和添加都適用,只是需要在所有接口中小心管理m_is_looping,避免重入的問題。優點是添加和刪除都適用,缺點是空間時間的效率損失最大。

            使用刪除標志延遲刪除的方法:對于刪除操作適用,也不存在其它地方刪除會出問題的情況,因為這個方法實際上是把循環中刪除的操作轉化為一個循環中更改的操作,所有迭代器都不會失效。即使刪除操作會導致容器內存重分配,這個辦法也可行,這是其優點,缺點是不能用于循環中添加的操作。
            博主弄復雜了,這種方法是治標不治本的,如果容器中裝的是拷貝刪成本很大的東西,這樣效率就低了。循環中刪的問題在于刪除操作之后,當前迭代器已經失效,因此無法更新之使其指向容器中的下一個元素。強行對迭代器進行 ++ 操作更新,會出現訪問異常。所以只要刪除之前,用一個額外的迭代器記住下一個元素的位置就行了。
            如下:
            //////////////////////////////////////////

            iterator it_this = containter.begin();
            iterator it_next;
            while ( it_this != container.end() )
            {
                it_next = it_this; // 之所以不直接使用 it_next=it_this+1
                ++ it_next;      // 是因為有些容器不支持隨機訪問,其迭代器不能直接 + n
                do_remove( it_this );
                it_this = it_next;
            }

            /////////////////////////////////////////////////////

            樓上的“僵尸狀態”也是一個辦法,不過正如它的名字一樣的,“僵尸”是個惡心的存在。程序在某一次循環中,把一堆元素標記為僵尸,這一堆東西必須要等到下一次循環檢查才能清理掉,如果沒有專門的定時清理機制,這個下一次有可能十分之一柱香之后,也有可能是一萬年,甚至有可能程序流程再也沒有這樣的下一次。在被清理掉之前那一堆僵尸在容器里腐爛發臭,占用空間內存,可能直到最后容器銷毀。可以增加專門定時清理機制,但是復雜度和成本又得另外計算。所以最好的辦法還是就地處決,并且毀尸滅跡。


            見過的最強的的布局管理器是WOW的。布局管理器一般實現得都靈活性不高,使用起來的代碼不比手寫MoveWindow少多少,能實現的布局也太有限。寫的好的像WOW那種的確實很強大,不過實現起來太費精力了,使用起來也不如MoveWindow直觀,反正我自己寫GUI框架是不寫這個的。
            這種人哪里都有的,樓主息怒。
            @OwnWaterloo
            我說的可能不大清楚,我的意思是“單件模式”只是一種概念,正是類似“全局數據”這種東西的一種抽象形容,不然何以稱“模式”。拿“單件模式”和“全局數據”本身比,是沒有可比性的,一為抽象,一個具體,一為模式,一為實例。它跟OO也沒有關系,一個C全局裸指針,也是一份單件的實體。所以不要再比來比去的了。

            把單件放在其它模式堆里,確實有點雞立鶴群的感覺,它并沒有其它模式那樣有啟發性,所有寫程序的人都知道世上有全局變量這個東西,那何必要取個好聽的名字像模像樣地研究一番呢,《設計模式》的偉大除了讓人學會到很多手法,還有一點就是統一了很多概念,并為之提供了許多標準的名詞方便大家研究,綜上所述,我覺得“單件”就是一個虛名,你喜歡叫它“全局變量”也行,大家心里的概念沒有差別,只是未必真是用全局變量來實現而已,所以不用在一個名字上糾結。

            誰不想用赤祼祼的全局指針,它們原始又純樸,天然無雕飾。可是真的要用它們來實現一份庫級別的代碼,就好像雙手拋飛刀一樣危險,不僅拋的人要兩眼圓睜神經緊繃,連觀眾都要跟著捏一把冷汗。全局變量本來沒有錯,錯的是在它們之上作出的許多美好的假設,假設誰一定在誰之前產生,誰一定在誰之后銷毀,誰依賴著誰,誰又被誰依賴著,誰是線程安全的,誰又一定不會被多線程訪問。互相完全沒有依賴關系,不用額外控制,像終結者一樣智能,完成任務又知道自己終結的全局變量,只是個傳說。

            有很多以單件名字的手法,Meyers 單件,Alexandrescu 單件,Phoenix 單件,Schwarz 計數器,你看它們好多都叫做“單件”,但是你喜歡叫 Meyers 全局對象,Alexandrescu 全局對象,Phoenix 全局對象 也可以。

            我個人覺得,把“全局變量”拿來和“單件”相提并論是很不妥的事件。就好像拿“汽車”和“交通工具”比一樣。不是一個層面上的東西,單件也許是全局變量,也可以不是,“全局”也有多種理解角度,存儲位置(堆上,棧上,靜態數據區),生存區域(線程局部,進程局部,模塊內部),生存周期(何時生,何時死,不死)。只是“全局變量”已經不能說明它的復雜度,但是一提“單件”大家都明白將要說的是什么,這就是“單件”存在的價值,這也是《設計模式》一書提出“單件模式”偉大所在。
            re: GUI框架:消息檢查者 cexer 2009-12-01 10:10
            @lch
            這個我同意。不過到后來的豐富控件,已經基本上是體力活了。

            re: GUI框架:消息檢查者 cexer 2009-11-26 17:28
            @lch
            一個是手段,一個是目的,何來重要和更重要之說。
            re: ffmpeg小試 cexer 2009-11-24 17:47
            最近開始研究 ffmpeg,關注一下博主。
            re: GUI框架:消息檢查者 cexer 2009-11-24 10:38
            【你那個MessageChecker怎么完成以一己之身完成,眾多不同功能的?
            同樣可以應用到message_checker 上,兩者是相通的,都是靠結構體中嵌的一個函數指針。】
            我的意思是函數本身不容易實現,只用函數主要有數據保存的問題。加上 function 來實現就容易了,直接綁定一些檢查函數和檢查的數據:
                typedef boost::function<bool (const Message&)> MessageChecker

                bool checkCommand( const Message& message,WORD id,WORD code );
                MessageChecker checkYesClicked = boost::bind( &checkCommand,_1,IDYES,BN_CLICKED );

                bool checkMessage( const Message& message,UINT messageId, );
                MessageChecker checkCreated = boost::bind( &checkMessage,_1,WM_CREATE );

            【其實我是被這段語法吸引的:
                window.onCreated += messageHandler( &::_handleCreated );
                window.onCreated += messageHandler ( this,&Window::_handleCreated );
            很像boost.signal。
            而且真正吸引人的是樓主說它是廉價工人~_~】
            += 之前的和之后的是兩個不同的東西,onCreated 是幫助消息映射的一個東西,其實就是一個轉發調用,所以成本很低。messageHandler() 是消息處理者和消息分解者共同組成的東西。在這里 ::_handleCreated 和 Window::_handleCreated 參數列表可以是不同的,這里和 boost.signal 不大一樣,因為一個 signal 只能對應一種 signautre 的 functor 的。

            【boost.function如果不用支持bind,可能可以不動用動態存儲。
            要支持bind…… 而且不使用動態存儲…… 好像不行……
            boost.signal肯定是要動用動態存儲的。】
            嗯。主要是管理起來很容易了,任何的參數直接綁定進去就行了,不用自己弄個堆對象來保存,然后還要記得刪除。

            re: GUI框架:消息檢查者 cexer 2009-11-23 20:09
            @陳梓瀚(vczh)
            【function的好處就是你可以使用子類的同時不用管delete啊】
            想了下用 tr1::function 來實現確實要比手寫類簡單得多,函數和參數綁定功能在這里很有用處,有多少參數都不用搞個多態的 Data 了,也不用自己去 delete 。確實很強大。

            re: GUI框架:消息檢查者 cexer 2009-11-23 17:31
            @陳梓瀚(vczh)
            【要堅定不移地使用這些東西。 使用tr1::function<bool(Message&)>,毫無管理復雜性,幾乎沒有效率成本。】
            把 MessageChecker::isOk(const Message&) 的實現放到 bool MessageChecker::operator()(const Message&) 中去,函數體MessageChecker 就變成了和 function 類似的東西,但這樣又有什么本質區別呢。tr1::function 的功能雖然強大,用它去實現消息檢查者,該寫的邏輯還得寫,省不了功夫,擴展性也是個問題。

            【至于什么是框架什么是類庫,有一個很容易的判斷標準:template method就是框架。】
            謝謝,很多書對這個也言之不詳,只是叫著爽就行了,所以我自己也就不大明白。我從此以后照你這個標準去評判好了。

            【而且,千萬不要去考慮標準庫里面什么類的性能如何的問題,你永遠假定他們是用魔法完成的,不需要任何CPU周期。不然你一行代碼都寫不出來。】
            我是從不考慮那些的:標準庫的效率再差,也不會到我放棄使用它們的地步的。另外以我的水平寫出來的東西絕對比它的慢,哪有資格嫌棄人家。

            【但是實際上windows的消息很亂,事件跟消息并不是一一對上號的。因此MessageChecker之類的東西最終用戶是看不到的,你要根據每一個控件的具體情況,重新整理出一系列事件,才能讓用的時候真正爽快起來。這里沒有技術問題。】
            你說得對,框架用戶是看不到 MessageChecker 的,他們看到的是 onCreated,onClosed,onClicked 之類的東西。

            re: GUI框架:消息檢查者 cexer 2009-11-23 16:57
            @陳梓瀚(vczh)
            【繼續攪局:你憑什么認為MessageChecker父類的成員變量一定夠用呢?如果夠用的話,就證明你的邏輯已經是固定的了,為什么要子類?就一個MessageChecker好了,不用繼承。你矛盾了。】
            歡迎攪局!你提出一問題確實有“以子之矛攻子之盾”的殺傷力,不過幸好我不是既賣矛又賣盾的。關于數據不夠用的情況 OwnWaterloo 的也提出過,你可以倒著往上看給 OwnWaterloo 的回復,在 MessageChecker 當中加一個多態的 Data 成員可以放下所有東西,我還是把這東西更新到博文里去吧免得又有人問。“邏輯”的關鍵顯然不是數據,而是那個檢查的動作。就像銀行存了五千萬,不拿出去揮霍也住不上豪宅一樣,成員變量夠用成員函數不夠用也是白搭,必須得要改寫。要想一個類,不繼承,不改寫,而要滿足不斷出現的需求,這肯定是不能完成的任務。“數據夠用”和“函數改寫”并矛盾。

            【類的靈活性在于,你使用shared_ptr<Base>保存了一個Derived*,然后調用虛函數。代價非常低,我經常把智能指針放進容器,也可以不管誰去釋放,總之會被釋放。而且我這種寫compiler的人對循環引用十分敏感所以我基本不會犯這種錯誤……】
            你是建議我把 MessageChecker 在堆上生成用智能指針管理起來吧。我也覺得這樣確實可以使用真正強大的虛函數,但這樣要付出每次都在堆上構造的效率成本和管理上的復雜性,而實際上大多數情況下這樣的付出是不必的:在 Windows 的消息機制下,消息檢查大多數時候需要的數據是很少的,用 WPARAM 和 LPARAM 就可以裝下,但確實有需要在堆上保存數據的情況,所以我在 MessgaeChecker 增加了一個多態的 Data 成員來保存,它只有極少時候的才會從堆上生成,這樣盡量避免了堆上生成的復雜性和效率損失,而完成的功能又絲毫不減。

            re: GUI框架:消息檢查者 cexer 2009-11-23 10:17
            @OwnWaterloo
            【框架定義了輪廓線,由程序員去填充顏色。類庫提供調色板等工具,由程序員去繪制。】
            這句話比喻得很好。你把框架理解成一種束縛是覺得需要按照它規定的方式去使用,但類庫甚至 API 何嘗不是也有自己的規則。我理解的框架和類庫其基本目的都是一樣的:對繁瑣的細節進行封裝,提供更為便利的接口。這當中肯定會損失靈活性,畢竟魚和熊掌很難兼得。但我覺得框架其實是類庫的進化后的身份,從字面意義上來講,“框架”看起來更有彈性,擴展的意思。但實際上大家對這兩個詞的概念并沒有很明白的分辨,比如說到 MFC,有人說框架有人說類庫大家的感覺都是一樣的。

            【這個,其實也是反的……OO是思想,class只是它的一種實現方式。也許使用會比較方便。但靈活性是不如函數+數據的。】
            我的想法相反。你說類的靈活性不如函數加數據,但類難道不正是建立在函數和數據之上的一個超強結合體?之所以用C之類的 OP 語言實現模式不如C++這樣的 OO 語言容易,一大原因正是它缺少類的支持。

            【message_checker ButtonClickingChecker(WORD id);
            message_checker xxxChecker( ... );】
            這是你舉例說明的用函數來實現檢查者。你可以嘗試真的用函數來實現消息檢查者,這個 ButtonClickingChecker(WORD id) , xxxChecker( ... ) 函數內部你各自要怎么實現?它既要包含不同的數據,又要包含不同的操作,它們返回完全相同的 message_checker 對象,這個 message_checker 又要怎么實現才能以一已之身完成眾多不同的功能?由于不同參數列表的函數實際上是完全不同的東西,你甚至不能以統一的方式保存它們管理它們。

            re: GUI框架:消息檢查者 cexer 2009-11-22 21:21
            cppblg 這爛程序,吃空格太嚴重了。

            re: GUI框架:消息檢查者 cexer 2009-11-22 21:05
            【不過我想了一個例子,比如我要在xxx-yyy時間段內,檢查這個消息,返回真,這個時間段外,就返回假。
            這個checker就做不到了。 肯定要放到其他地方做,比如hanlder中。】
            是可以的啊,可以像下面這樣實現。
                class TimeMessageChecker:public MessageChecker
                {
                public:
                    TimeMessageChecker( timeStart,timeTo )
                        :MessageChecker( 0,timeStart,timeTo,&TimeMessageChecker:virtualIsOk )
                    {}
                protected:
                    static bool virtualIsOk( const MessageChecker* pthis,const Message& )
                    {
                        timeNow   = GetCurrentTime();
                        timeStart = pthis->wparam;
                        timeTo    = pthis->lparam;
                        return timeNow>=timeStart && timeNow<=timeTo;
                    }
                }

            可能你的意思是遇到消息參數裝不下檢查時需要的信息的情況應該怎么辦,這里舉例說明一下怎么實現。比如說要檢查是否某個字符串,這樣的實現可以裝下任何需要的信息。
            先定義一個多態的數據類型,為了效率這里可以使用引用計數之類的東西
                class MessageData
                {
                public:
                    virtual ~MessageData()
                    {}
                    virtual void release()
                    {
                        delete this;
                    }
                    virtual MessageData* clone() const = 0;
                };

            MessageChecker 當中有這個成員
                class MessageChecker
                {
                //......
                public:
                    MessageData* data;
                }

            修改拷貝構造函數和析構函數
                MessageChecker::MessageChecker( const MessageChecker& other )
                {
                    if ( data )
                    {
                        data->release();
                        data = NULL;
                    }
                    if ( other.data )
                    {
                        data = other.data->clone();
                    }
                }

                MessageChecker::~MessageChecker()
                {
                    if ( data )
                    {
                        data->release();
                        data = NULL;
                    }
                }

            定義一個裝字符串的多態數據類
                class StringMessageData:public MessageData
                {
                public:
                    StringMessageData( const String& str_ )
                        :string( str_ )
                    {}
                    virtual MessageData* clone() const
                    {
                        return new StringMessageData(string);
                    }
                public:
                    String  string;
                };

            利用數據成員 data 所裝的信息可以檢查字符串的消息檢查者
                class StringMessageChecker:public MessageChecker
                {
                public:
                    StringMessageChecker( const String& string )
                        :MessageChecker( 0,0,0,&StringMessageChecker::virutalIsOk )
                    {
                        data = new StringMessageData( string );
                    }
                public:
                    static bool virtualIsOk( const MessageChecker* pthis,const Message& message )
                    {
                        StringMessageData* data = (StringMessageData*)pthis->data;
                        if ( !data )
                        {
                            return false;
                        }
                        std::string stirngToCheck = (const Char*)( message.wparam );
                        return stirngToCheck == data->string;
                    }
                };

            【對,這就是我對"框架"感到反感的地方之一 —— 它"限制"你做事的方法。不對它熟悉到一定程度,就沒法工作……
            作為程序員……我也了解用戶的需求是很惡心的…… 就像你有一篇blog里寫的那樣……所以,推己及人……對我提出的這個惡心的需求,聽過之后就當是廢話好了~_~】
            說實話我一直對“框架”和“類庫”的概念分不大清楚,我想“框架”從名字上來說多了一個“可以擴展,可以填充”的意思,沒有你說的“限制你做事的方法”這種感覺。還有你提到了 GUI 框架用戶的需求。要說明一下的是,實現的這個消息檢查者只是在框架內工作的,方便 GUI 框架的開發者和擴充者使用,GUI 框架的使用者不會接觸到這個東西。最終的用戶只需要使用是像這個樣子:
                window.onCreated += messageHandler( &::_handleCreated );
                window.onCreated += messageHandler ( this,&Window::_handleCreated );

            共4頁: 1 2 3 4 
            久久久久这里只有精品| 国产女人aaa级久久久级| 久久久久久久波多野结衣高潮| 久久男人AV资源网站| 97精品国产97久久久久久免费| 99久久久精品| 亚洲综合久久夜AV | 精品熟女少妇av免费久久| 国产精品欧美久久久久无广告 | 要久久爱在线免费观看| 色综合久久久久无码专区 | 久久精品免费全国观看国产| 狠狠色丁香久久婷婷综合| 一本伊大人香蕉久久网手机| 国内精品久久国产| 国产ww久久久久久久久久| 香蕉久久夜色精品升级完成| 狠狠色综合网站久久久久久久 | 国产精久久一区二区三区| 囯产精品久久久久久久久蜜桃| 欧美伊香蕉久久综合类网站| 亚洲AV无码久久精品蜜桃| 午夜精品久久久内射近拍高清| 人人狠狠综合久久亚洲婷婷| 亚洲国产精品无码久久98| 久久婷婷午色综合夜啪| 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久综合精品国产一区二区三区| 国产精品岛国久久久久| 一本一道久久综合狠狠老| 人妻精品久久久久中文字幕| 国产 亚洲 欧美 另类 久久| 国产亚洲婷婷香蕉久久精品| 久久精品国产亚洲AV无码娇色| 少妇熟女久久综合网色欲| 三级片免费观看久久| 亚洲国产日韩欧美久久| 一级a性色生活片久久无少妇一级婬片免费放| 久久久精品午夜免费不卡| 久久青青草原综合伊人| 色综合久久久久网|