• <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 - 16,  comments - 34,  trackbacks - 0
            共10頁: 1 2 3 4 5 6 7 8 9 Last 
            re: C++實用技巧(二) OwnWaterloo 2010-06-24 10:33
            @zuhd
            剛發現…… 那一天收到的通知太多, 被我直接全部標記為已讀, 然后忘了……
            通常用同名gmail郵箱, qq不怎么用……
            re: C++實用技巧(二) OwnWaterloo 2010-06-24 04:53
            >>0指針代表的是沒有指向任何有效對象

            空指針的二進制表示并不一定是全0 。
            浮點數也一樣, 0.0f, 0.0, 0.0lf的二進制表示都不一定是全0。
            所以, 即使是C語言, 欲使用memset去將指針初始化為空, 或者將浮點初始化為0, 都是不可移植的。


            >>30 String& operator=(const String& s)
            >>31 {
            >>32 delete[] buffer;
            >>33 buffer=new char[strlen(s.buffer)+1];
            >>34 strcpy(buffer, s.buffer);
            >>35 }

            這個實現有問題, 當出現自賦值的時候:
            String s;
            s = s;
            this->buffer和s.buffer是同一個指針。
            32行delete之后, 已經是dangling pointer。
            33行傳遞給strlen, 34行傳遞給strcpy都是錯誤的。


            要么判斷自賦值的情況:
            if (this!=&s)
            {
            delete[] buffer;
            size_t len = strlen(s.buffer)+1;
            buffer = new char[ len ];
            memcpy(buffer, s.buffer, len );
            }

            但是, 如果new新的buffer時出現異常, 就會導致this有一個dangling pointer。
            為了安全, 可以先new, 再delete:
            size_t len = strlen(s.buffer)+1;
            char* p = new char[len]; // 之后操作都不會產生異常
            memcpy(p, s.buffer, len );
            delete[] buffer;
            buffer = p;

            先new再delete也可以不用判斷自賦值的情況了。
            @博主
            規范。

            二元操作符始終會將操作數轉換為同一類型計算。

            轉換規則很復雜, 但有2點:

            1. signed T的rank一定比unsigned T要低
            2. int 剛好超過默認參數提升的范圍

            所以 int op unsigned 一定是都轉換為unsignd計算。
            printf("%d %u\n", ni-ui, ni-ui);
            printf("%d %u\n", (ni-ui)*2, (ni-ui)*2);
            printf("%d %u\n", (ni-ui)/2, (ni-ui)/2);
            printf("%d %u\n", (ni-(int)ui)/2, (ni-(int)ui)/2);

            觀察輸出結果, 明白了嗎?
            @dudu
            >> 一個大家公認的簡單清晰的代碼規范

            異常對于你們不清晰? 怪誰? 怪你沒入"技術流"?

            并不是大家公認, 使用異常的語言是越來越多, 只是你們不求進步而已。
            要說公認, 也就是固步自封流公認罷了。
            @那誰
            默認構造函數的行為是"可預測"的。
            就在你文章第1段中提到的書"inside C++ object model"中就有。
            最關鍵的一句話: "編譯器合成的構造函數, 只為滿足C++的需要, 而不是程序員的需要。"


            所以, 默認構造函數的行為是"可預測的", "確定的", 即 —— 具有trivial construct語意的member, 不會被初始化, 而是包含隨機值。


            關于隨機值的兩種處理:
            FILE* f;
            ...
            f = fopen( ... );

            還是
            FILE* f = 0;
            ...
            f = fopen( ... );


            后一種所謂的"規范寫法", 在我看來完全是多此一舉。
            當然, 如果你真的需要這種多余的動作:
            struct T {
            ... no constructor
            };

            T v = T(); // 不再是隨機值。 v中的每個值都是確定的。
            @陳梓瀚(vczh)
            >>但是一個團隊使用相同的編譯器是應該的
            這也就暗示了C++庫最方便的復用形式是源代碼, 而不是二進制。


            >>其他語言的Exception都有Message,這個可是好東西啊……而且catch(...)不能處理基本錯誤,譬如說access violation,還有divided by zero等等。
            其他語言可以 throw 1212么? 1212怎么message?
            SEH可以處理那2種, 還可以轉化為C++ exception。 但是, 非Windows下?

            其他語言是通過"限制能夠被throw的對象的類型" —— 比如必須繼承自Exception;
            來達到使用catch (Exception e)就可以處理所有異常的目的。

            C++沒有這一限制, 需要自我限制。


            其他語言是通過某些平臺相關的機制: 比如SEH來處理access violation;
            或者是通過損失基礎運算的效率: 比如
            T& dereference(T* p) { if (p) return *p; throw nullptr_exception(); }
            unsigned plus(unsigned x, unsigned y)
            {
            if (UINT_MAX-x>y) return x+y;
            throw overflow_exception();
            }
            來得到這些錯誤的異常。

            C++不會添加這些保姆工作。


            所以, 其實也不算C++ exception相對于其他語言的劣勢, 只能算一種權衡。
            默認情況下, 不限制可拋出類型, 可以通過catch (...)來處理所有。
            如果需要, 可以自我規定一個基類。

            默認情況下, 不檢測基本運算的錯誤。
            如果需要, 自己檢測并拋出。
            @陳梓瀚(vczh)

            >>1.在我的眼里,throw就如同if,如同for,如同while,如同break,如同continue,如同return,僅僅是一種跳轉機制。
            而且, 這種跳轉機制我認為比goto/longjmp要好理解, 因為它是結構化的。

            >>2.市面上所說的throw的危險程度,排除了因為程序員的畏懼而不學習之外,唯一說的過去的無非就是throw很難在ABI上得到兼容。
            嗯, exception真正從技術上不能被使用的原因就只有效率和二進制兼容性。
            其他都是"人文原因", "市場原因","成本原因", "金錢原因"。

            btw: 你發覺C++的二進制兼容性會闖禍了~?


            >>4. ... 因為他們心里沒譜,沒有catch(Exception e)這種萬能東西可以用 ...
            這倒不難, 敢用exception肯定要人為規定一個最終基類。
            即使沒有這樣的基類, 還可以catch( ... )
            re: Python Ogre Blender OwnWaterloo 2010-05-31 17:26
            有人曾經專門發系列文章批評Dive into Python。
            而且批評的原因中有一點: 陳舊。
            自己看著辦吧……

            python不錯吧~_~
            這代碼, 換個人來也也差不多是這個樣子。

            程序員有時候就是賤……
            抬舉他, 給他以選擇, 他就亂來了……
            貶低他, 給他以束縛, 他就老實了……
            @那誰
            java程序員也可以說自己"基本用不著指針", "手工內存管理給我帶來了很多困擾"。

            是否美觀并不是我臆斷, 這可以使用完成同樣功能(當然, 除了效率、以及二進制兼容行上不同)的代碼進行對比。 只是cppblog對貼代碼并不友好。
            所以, 我給出了劉未鵬一篇文章的鏈接。
            里面有完成同樣事情, 錯誤代碼如何做 vs 異常如何做 的代碼片段。

            如果你對異常處理沒經驗, 錯誤代碼肯定很有經驗吧?
            1. 即使不能處理, 也必須檢測 —— 因為需要向上層報告
            2. 這些檢測, 重復出現在每個層次, 每個調用點
            3. 檢測代碼與邏輯代碼混雜
            4. 即使錯誤最終報告到一個可以處理的層次, 信息早就丟得7788了, 只剩下EINVAL這種含義模糊, 不知道應該如何應對的錯誤代碼。

            這些是否是實情?難道你不覺得這些手工的機械重復是不美觀的?
            而異常處理就是為了解決這些問題。


            原始也不是臆斷。 理由上面也有: 越來越多的語言開始加入異常機制。
            C++很早就加入了, 卻被程序員不分青紅皂白的拒之門外, 是否原始?
            @那誰
            我說的是OpenCV和apr的內存管理部分的質量, 請仔細看。

            還是那句話: 不學, 什么都困難。
            這種所謂的"C++應該避免使用異常"和java程序員所謂的"應該避免使用指針, 所以我們使用java"有什么區別?


            "異常的使用導致了程序的走向難以從代碼中一目了然的看出來,給問題定位帶來困難." —— 而這才是你的偏見。
            就你這句話就能推斷你沒什么使用異常的經驗, 而是出于對異常的不理解與恐懼。
            請問我說錯沒有?
            @那誰
            "我里面提到的,由于引入了異常,導致代碼走向難以預測,這一點如何解決?"
            你這個問題就像:
            由于引入了指針(甚至雙指針), 導致代碼難以理解,充滿bug, 這一點應該如何解決?
            難道我們應該放棄指針(和雙指針)?

            "指針"還可以替換成很多東西。

            一句話, 不學, 什么都難以理解。
            如何解決?
            1. 讓代碼保持異常安全 —— 無論異常是否發生。
            什么游戲都需要規則,這是使用異常的最關鍵規則。
            pthread_cancel有相應的cancellation safety。
            信號有相應的可重入。

            2. 如果沒有異常需要處理, 讓異常直接向上報告 —— 無須任何額外代碼
            而使用狀態代碼, 即使某個層次不能處理錯誤, 也必須編寫代碼去檢測, 并向上報告(除非想吞掉這個錯誤)。
            "每一層", "每一個調用點"。

            狀態代碼不優美的地方之一 —— 太多重復代碼, 這些代碼并不是為了處理這個錯誤, 僅僅是為了向上報告錯誤, 所以不得不編寫代碼去檢測。

            不優美的地方之二 —— 檢測代碼和happy path代碼混雜在一起, 使得happy path中至少一半代碼都是和邏輯無關的, 所謂的噪音。
            上面記號系統中說過, 積分記號確實需要學習成本, 但換來的好處就是用最少的噪音表達出盡可能多的信息。

            不優美的地方之三 —— caller和callee之間報告錯誤所使用契約的耦合。
            當caller是一個普通的函數這個問題還不突出。當caller是一個函數模板, 對應的callee根本不知道是何物時, 如何定義callee和caller之間的報告錯誤的契約?
            "0表示Ok, 非0表示有問題, 問題寫在errno" 而errno這種全局的東西帶有全局的一切毛病, 比如:如何分配一個獨一無二的code?

            3. 如果需要處理當中的部分異常, try之, 并僅僅catch感興趣的異常, 處理之。
            接上面的, 如果不能得到一個獨一無二的code, 就無法知道究竟是出了什么毛病。
            EINVAL? 哪一個參數有問題? 什么問題? 信息早就丟了。
            無法有針對性的進行處理。


            更多的, 請看:
            http://blog.csdn.net/pongba/archive/2007/10/08/1815742.aspx


            而google coding style中所謂的不使用exception的理由, 在知道什么是異常處理的人的眼中, 只有最后2點是站得住腳的:
            最后一點, 也就是上一個回復說的"與其規定什么時候可以用, 應該如何用", 不如直接"全面禁止" —— 因噎廢食。

            倒數第2點, 就是效率問題。 在"效率攸關"的地方, 確實不能用。
            但這種地方并不是想象中的那么多。

            其他都是扯談。 要么寫這個規范的人不懂exception, 要么就是他懂, 但故意牽強附會, 或者危言聳聽。


            另外, 這種高壓政策下的google的代碼我沒看過, 所以無法評論其質量高低。
            但肯定是"原始且不美觀"的。
            而這種在高壓政策下產生出的"原始且不美觀"的其他代碼我倒是看過, 例如OpenCV和apr中的內存管理部分 —— 在這種"泯滅人類的思維與創造性, 僅僅將人作為制造code的工具"的高壓政策下壓榨出的代碼, 質量怎么可能高?
            @那誰
            一說就起勁了……

            再說說操作符重載。 equals add vs ==, +

            記號系統的嚴謹與簡潔都很重要。
            以前我也只注重記號系統的嚴謹, 認為嚴謹的就是易讀、易理解的。
            直到讀了這篇文章:
            http://www.ibm.com/developerworks/cn/xml/x-matters/part24/index.html

            清單3中的xml就是嚴謹而不簡潔的。 即使不學習任何新事物, 也大致能猜出清單3表示的是什么內容。
            而清單2的記號系統就是簡潔的, 同時也是嚴謹的 —— 只是需要學習這套記號系統。

            如果不學習清單2中的記號系統, 那清單2可能就是天書。
            如果學習了, 那清單2就幾乎是"用極少廢話作輔助, 表達作者的意思"。

            而清單3,無論是否學習, 都是很羅嗦的在表達作者的含義, 包含了太多的噪音。

            我覺得(只是覺得, 因為歷史不能重演), 如果微積分的記號系統不是隨微積分一起產生, 微積分是發展不起來的。
            將表達式中的Sx 全部替換成 interal(x); 記號是不需要學了, 但這表達式根本沒法讀。

            所以, 不是簡潔的記號系統不可取, 而是記號系統在簡潔的同時還要保持直觀, 嚴謹, 無歧義。
            要設計出這樣的記號系統是需要精心的、 全局的、 周詳的準備。
            而C++的操作符重載讓記號的引入變得太容易, 獲得簡潔的同時容易丟失其他方面的因素。

            上面回復已經說到google中C++程序員的素質。
            與其于讓他們理解直觀、嚴謹、無歧義, 直接讓他們不許使用新的記號系統可能更省事。
            但無論如何, 這所謂的"高標準"的規范, 其實只是"無奈"之舉, 而非"進步"。
            @那誰
            "C++某特性不理解,產生畏錯心理(或者已經得到教訓);
            對此采取的措施不是去學習與理解這些特性, 而是放棄這些特性。"


            對筷子不熟悉,不嘗試學習與熟練,而是放棄 —— 這也不是不行, 畢竟用刀叉(甚至手抓)也算是吃飯 —— 但是, 如果是中餐的話, 這并不是什么值得為之感到光榮的事。


            吃飯不同于軟件開發的地方是:
            餐桌上的同伴吃中餐不用筷子最多最多讓人感到難堪。
            而項目中的隊員如果做不到步調一致, 就可能導致項目失敗。
            但是, 相比這飯吃得是否得體, 步調一致更為重要。
            所以, 為了那些因噎廢食的人, 不得不同他們一起"吃手抓飯", 從而達到步調一致, 也是很無奈的事。
            —— 這依然不是什么值得炫耀的事情。


            在正常控制流中插入的另一條控制流是異常的關鍵。
            正是這條非尋常的控制流, 導致學習成本。
            如果愿意去學習這條控制流的規則, 就能得到這條控制流帶來的好處:
            它確實將“錯誤的檢測與處理”給分開了。
            —— 中餐是否值得吃,就是在學習成本與所有層次上的所有錯誤都必須“手工地”檢測并向上報告(即使不處理任何錯誤)之前做選擇。


            越來越多的語言加入異常處理機制(甚至是一些原本沒有的語言)。
            并且, 在正常控制流之外的控制流并不只在異常處理中出現: 信號, thread_cancel都有,

            要么“永遠逃避所有使用非正常控制流的技術”。
            —— 永遠不去學習如何使用筷子。

            要么去學習任意一種, 并舉一反三。
            —— 學習筷子的使用后, 品嘗中餐的諸多菜系都有基礎了。


            關于google, 我感到困惑的是: 對google中的python和java程序員是否也有不許使用異常的規定。
            我想應該是沒有的。
            那么, 換來的結論就是: goolge中的C++程序員, 對異常這種編程思想的理解, 還不如google中的python和java程序員。
            因噎廢食
            請問一下, 這個同:
            http://m.shnenglu.com/romangol/archive/2009/10/26/99460.html
            有什么不同嗎?
            修正了一些bug?
            re: SASL 的 Name Mangling OwnWaterloo 2010-05-25 00:34
            @空明流轉
            哦, 這樣……
            為什么要新造一門語言呢? —— 如果這個問題過于無聊可以無視……
            我只是想收集一下創造一門語言的n個理由……
            謝謝……
            re: SASL 的 Name Mangling OwnWaterloo 2010-05-24 23:59
            SASL是什么? google了一下, 好像都不是……
            @匿名
            知道什么叫"舉一反三"嗎?
            @OnTheWay
            注意兩種需要運行時初始化的靜態對象, s和s_。
            前者的初始化時機C++有保證, 但不保證多線程安全。
            后者的初始化時機C++只保證同一翻譯單元內中有順序。

            再看static CAssistForSingleton m_refSycObj;
            這就屬于第2種。

            下面的情況有發生的可能性:
            1. 另一翻譯單元的靜態對象先于m_refSycObj被初始化
            2. 在它初始化時訪問了CSingleton *GetInstatnce()

            此時就訪問了一個"未初始化"的臨界區。
            這已經是bug。

            再有, 如果有下列情況:
            1. 一些先于m_refSycObj初始化的代碼開啟了線程
            2. 多個線程在m_refSycObj初始化前訪問CSingleton *GetInstatnce()

            一個未初始化的m_refSycObj根本不能用于同步。

            所以, 上面的第1個問題: 這樣做不是多線程安全的。


            而靜態對象在構造時啟動線程的情況并不多, 所以并不一定需要將s_作成多線程安全。
            例如boost就是這樣, 要求在進入main之前, 是不許有兩條以上的執行路徑去訪問。
            這就是第2個問題。


            如果需要完全的多線程安全:
            1. 使用once_initial函數(pthread或者win6有提供)
            2. 使用"可以靜態初始化"的鎖, 比如pthread_mutex_t就可以
            或者自己使用一個spinlock也行。

            我沒有msn…… 用gmail的同名郵箱。
            @OnTheWay
            再來一種:

            class S
            {
            // ctor, copy, dtor, assignment
            static S s_;
            public:
            S& instance() { return s_; }
            };

            S S::s_;

            同樣是上面的問題。
            @OnTheWay
            class S
            {
            S() { ... }
            ~S(); { ... }
            S(S const&);
            S& operator=(S const&S);

            public:
            static S& instance()
            {
            static S s;
            return s;
            }

            };

            你認為C++(C++03)是否保證S::instance是線程安全的?
            如果是, 請說明理由。
            如果C++不保證, 是否應該將S::instance作成線程安全的?
            re: It's never too late OwnWaterloo 2010-05-21 15:48
            矯情-_-
            依然不是線程安全的。
            re: 高質量c/c++編程讀書筆記(1) OwnWaterloo 2010-04-09 17:41
            又見這本垃圾書。
            除了第1條, 其他全是狗屁。
            re: 對 C++ 歷史的個人觀點 OwnWaterloo 2010-04-09 16:58
            @陳碩
            MFC、QT、ACE太老是吧? 來個新點的?
            http://www.libnui.net/

            去看看它是什么時候開始開發的, 又重復發明了多少輪子吧。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-09 15:09
            @溪流
            你這個問題很好解決~
            找個現代點的ide...
            re: 對 C++ 歷史的個人觀點 OwnWaterloo 2010-04-07 21:25
            @唐風
            TL上跑題太嚴重, 看吧, 沒幾樓就扯到profiling, 扯到“大部分應用都合適了”。
            如果萬事都扯這么多無關的東西, 就沒什么好討論了。

            allocator的問題不在于是否應該有allocator參數,是否應該將allocator作為模板參數。
            上面已經說了:

            1. 如果一個container沒有allocator參數
            那它內部的分配方式必然不能被定制, 它綁定了一個“策略”。
            當這種策略無法滿足用戶要求時, 整個container的實現連同這個策略一起被拋棄。

            2. 模板vs非模板參數
            上面也說了, 模板是非模板的一個范化形式。
            模板可以得到非模板的東西, 只要實例化一次即可。
            反之不行。
            當template alias加入語言后, 使用模板的設計會更優雅。


            allocator真正的問題是標準對allocator的狀態的描述很模糊。

            如果同一allocator type的所有instance都可以被認為是相同的 —— 也就是說,A和B是同一個個類型的2個instance, 從A分配的內存可以由B釋放 —— 那沒問題, 可以安全的和STL配合使用。

            但通常, allocator都需要per instance的狀態才能發揮真正作用。
            而這種帶有per instance狀態的allocator和STL交互, 標準說得很模糊。

            如果標準規定STL的實現必須注意這個問題, 那allocator就非常好用。
            絕對不存在lz所說的“基本用不上”。
            即使就是現在的情況, 也可以用一些方式繞過去, 只是很不美觀。

            綜上, allocator的設計應該被改進(取消這個限制), 而且依然作為一個模板參數。


            btw:如果C++0x真引入了template alias,boost的智能指針就是一坨垃圾, 無論它設計多少個, 在Loki面前都是垃圾。
            re: 對 C++ 歷史的個人觀點 OwnWaterloo 2010-04-07 16:37
            @wuqq
            C++不玩那套, 別拿其他語言的什么接口/實現那套玩意來“套”C++的設計。
            allocator是一種規范。
            整個STL都是在這種duck typing的基礎上構建起來的, 而不是java或者C#那種接口式的設計。


            如果你確實需要按接口的方式來使用, 自己實現一個滿足allocator規范的接口, 假設叫IA。
            然后使用vector<T,IA> 即可。
            無論你使用什么IA的實現, 你都可以使用vector<T,IA>類型。
            甚至可以使用0x中的新的特性:
            template<typename T>
            using your_vector = std::vector<T,your_allocator<T>>;
            your_allocator是一個模板, 轉發到IA上。

            然后就一直使用your_vector就行了。


            模板和接口就是在效率與代碼體積上的權衡。
            但是, 用模板實現的代碼, 如果在乎代碼體積, 可以輕易轉換為接口去使用。
            并且獲得接口的所有好處, 例如不暴露實現。
            反之, 如果一開始就用接口,當需要模板的行為時, 就沒得搞, 永遠沒辦法, 除了重寫。


            vector太麻煩, 換個例子。
            如果將排序算法使用模板實現:
            template<class RanIt, class Cmp>
            void sort(RanIt first, RanIt last, Cmp c);

            那么, 這個模板可以輕易轉換為C語言中使用void*和int (*cmp)( ... )的qsort, 也可以輕易轉換為使用接口作為Cmp和RanIt的sort。
            同時, 不暴露這個模板的任何實現。
            你可以將這個模板隱藏到實現文件中。

            反之, 如果sort一開始就是qsort或者使用接口:
            當你確實需要效率,確實針對不同類型生成另一套代碼的時候, 你必須重寫。

            這就是模板的強大之處, 它的使用是很靈活的, 看你的需求而定。
            你不僅僅可以“直接使用”, 你還可以將它作為“代碼生成器”, 生成滿足你需要的東西。
            re: 對 C++ 歷史的個人觀點 OwnWaterloo 2010-04-07 01:58
            ———— integers

            >> integers 固定長度有什么好處?或者說為什么 <stdint.h> typedefs 沒有解決問題?

            scanf/printf這個你已經說了, inttypes.h
            而cin/cout更不用說了, 因為有重載。

            >> 在 C++ 里,可以用函數重載 (overload) 來解決。但是 typedef 并不真正引入新類型(golang 與此不同),你如何知道 int_fast32_t 與 int64_t 是不是同一類型呢?另外還有 size_t/time_t 呢
            你真的需要嗎? 真的需要有is_same_type這種東西。

            你通常你需要做的就是像cin/cout那樣, “對類型本身, 而不是各種typedef”去重載。
            比如:
            void f(char x); void f(int x); ...
            然后無論uint64_t和size_t是什么, 都可以f之。

            或者使用enable_if這種機制。

            java和C#那套東西, 只是在當前的pc機已經服務器上行得通。
            比如它們要規定整數長度, 規定浮點規格, 甚至連char都規定了。
            但這是很短視的作法。

            這兩門語言所說的unicode, 其實只是utf16。
            我不知道usc4流行起來的時候, 這兩門語言打算怎么辦?
            又搞出個wchar?
            或許那時候它們早就滅亡了。

            而對其他各種古怪的平臺, 我也不知道java se和.net compact活得怎樣。
            我只想知道, 在16位的平臺上, 32位的int是否總是要由2個機器字拼出來。
            甚至, 在8位平臺上, 是否需要4個機器字來拼。

            而這兩門語言又希望做到強類型, short的使用不是那么愉快:
            short s = ...;
            s = s + 1; // error
            s += 1; // ok

            C語言肯定是打算盡可能貼近機器的, 而不是貼近程序員的。
            所以C標準不會規定確定長度的整數, 即使C99中, 那些typedefs也是optional的。

            而C++, 這個就有分歧了。
            我是希望C++依然能貼近機器。
            畢竟, 如果真的需要開發起來很爽, 已經有java或者C#了, 直接用就是了。

            如果讓C++規定整數長度, 而提供:
            typedef xxx nature_width_t;
            并大量使用之, 我覺得很難接受。



            ———— finally

            >> finally 有什么用?確實可以用棧上對象析構函數里的動作來模擬 finally,這又是一個 idiom,為什么不正大光明地讓語言支持這一常用功能呢?

            這一功能常用嗎? 在我看來, 它只是沒有確定性析構時機的語言中的一種“補救措施”。
            不能因為其他語言有這個, 就一定要搬到C++中。

            C++不需要這種爛玩意, 請允許我說它是爛玩意。
            為什么? 因為finally會造成“執行代碼與回滾代碼”分離兩處 —— 相信你明白我的意思。
            所以C#會早早引入using, 而不思進取的java也終于打算在java7加入類似的機制。

            所以, 這種東西只會讓代碼寫得更爛, 而不是更好。
            這是最主要的原因。


            其次, “讓資源歸類所有”, 這在C++中已經被廣泛接受了, 是這樣嗎?
            所以, 在很多時候, C++都可以將action和rollback寫在一處。
            而實現一個范型的RRID類, 其實Loki已經有ScopeGuard而boost也有scope_exit。
            當語言支持auto和lambda之后, 它們都不再需要使用語言的陰暗角落或者晦澀的語法。
            可以實現的十分優雅, 用戶代碼也可以寫的十分優雅。

            而且auto的實現并不難, 編譯器必然是知道某個表達式的類型。
            lambda應該也不難, 很多時候那些手寫的functor都是有規律的, 很適合讓機器自動生成的。
            而finally的實現方式, 我就不清楚了。

            ———— 默認值

            >>解釋2:數據成員的默認值有什么用?

            我依然沒看出有什么用。
            你舉的例子, 其實是C++0x打算支持的“轉發構造函數”可以優美解決的。

            而且, 據我所知, C++0x也是打算支持這樣的特性的, 我忘記叫什么名字了:
            class X {
            T v = default_value_for_v;
            };

            注意, 我的觀點不是排斥這種特性。
            我反對的是將這種行為“作為默認行為”。
            我希望默認情況下, 語言不要做多余的事情, 除非我顯示要求。

            —— allocator
            我看了你給的鏈接, 沒發現有具有說服力的例子。

            1. 當你不需要定制allocator。

            無論那種設計, 都不會對你造成影響。

            2. 當你需要定制allocator。

            無論那種設計, 你可能都需要將兩種容器區別對待。
            也就是說, 你這種要求:
            >>但這完全沒道理,我不過想訪問一個vector<string>,根本不關心它的內存是怎么分配的,卻被什么鬼東西allocator擋在了門外。

            不過想訪問一個vector<string>的要求, 本來就是不合理的。
            你只考慮到了“使用allocator會有什么壞處”, 卻沒想過“不使用allocator你同樣會遇到這些問題”。
            所以, 這并不是allocator的錯。

            而使用allocator的設計, 你至少不需要去重新實現一套數據結構。

            當然, STL對allocator的設計并不是很好。
            比如它要求不同的allocator必須被認為是同一個。
            所以會導致這樣的問題:
            >> 那么每種類型的allocator必須是全局唯一的(Singleton)

            C++應該取消這個限制, 而不是取消allocator。


            在你所說parser的case中, 你的目標是這樣對嗎:
            一個allocator的類型有不同的實例, 這些實例是不在線程之間共享的。

            那么, 這些container本身也是不在線程間共享, 依然可以用allocator解決。
            只是它會觸犯STL對allocator的限制。


            —— 各種庫, auto_ptr, valarray, xml, log

            >>auto_ptr 為什么是壞的,因為太容易用錯,且不能放到標準容器里。

            C++什么東西是“不容易用錯的”?
            (而且, 當你允許工程使用boost之后, 你會遇到更多容易用錯的東西)


            這和finally還不同。
            學會finally之后, 寫出的代碼依然是臭的。
            而auto_ptr, 至少在學會之后, 它還是有用的。


            valarray的slice我還確實沒用過。


            對, auto_ptr, valarray, vector<bool> 都是有各種各樣的毛病的。
            但是, 既然他們已經被加入標準庫了, 對付這些毛病的辦法就是去“學”。
            移除是沒法移除的。 早就被deprecated的strstream到現在都可以使用。
            vc10, gcc4.4.0), vc10甚至一個警告都不給。

            而且, 它們(包括strstream)對會使用的人來說并不是一無是處。
            就我來說, 我并不需要scoped_ptr, 或者說不會因為這樣一個小東西去引入boost,或者將編譯器限制到支持C++0x的那些上。

            vector<bool> 和valarray都是試驗品。
            如果你需要一個可增長的位圖, 你還是得去實現vector<bool>那樣的東西。
            使用上還是需要注意將他們和STL其他容器有所區分。
            那么, 移除它能獲得什么好處?

            valarray就讓它呆那里就可以了, 會給你帶來負擔嗎?


            —— xml和log

            你說的這個問題, 是不能靠語言提供標準庫來做的。
            很簡單, Qt用std::string了嗎? ACE用了嗎? MFC用了嗎?


            你可以說std::string設計得差, 設計得太學術。
            你也可以說上面那些庫不屑于使用模板。

            但是, std::xml, std::log難道不會重蹈覆轍?
            上面討論的那幾個家伙(auto_ptr, valarray, vector<bool>)已經犯錯了。

            同時, 正因為我們看到這些不夠完美的東西, 對待標準庫時我們更需要“謹慎”。
            我覺得標準委員會做得很好, 甚至將concepts砍了都做得很好。
            就是兩個字“謹慎”。
            沒有它們, 依然還在開發; 但如果因為沖動加入它們, 可能就是以后無法移除的負擔。
            就像上面那幾個。

            目前這種模式: 將boost作為試驗田, 等有充分使用基礎之后再納入tr1, 我也覺得很好。


            C++需要的是穩定, 只把必須加入語言的東西加入,(移除就更沒必要了) 其他的慢慢觀望。
            我寧愿使用一個從vc8-vc10, 從gcc3-gcc4都可以使用的C++。
            而不是告訴用戶, 你必須使用什么編譯器的什么版本。

            C++不像C#那樣, 可以霸氣的說“我就是不向后兼容,你拿我怎么招?” “你不還是得用我?”
            re: 對 C++ 歷史的個人觀點 OwnWaterloo 2010-04-06 22:38
            個人覺得很多改進都是不切實際的。

            —— Exact-width integer types

            沒有必要。
            當需要確定寬度的整數類型時, 應該使用stdint.h那樣的typedef。(據說C++0x也會引入相應的cstdint)
            而不是一開始就將數據類型固定死。

            而且,即使是C99, Exact-width integer types也是optional的。
            也就是說,確實是不能保證在每個平臺上都有確定寬度整數。
            更有用的應該是Minimum-width integer types
            或者Fastest minimum-width integer types

            —— finally
            引入finally還不如引入lambda和auto。
            有了lambda和auto, 配合RAII, finally就不值錢了。
            而lambda和auto也是C++0x準備加入的。

            —— default value
            這能有什么用?
            C和C++給程序員最大限度的控制。

            struct X x;
            X_fill(&x); // 明明知道x馬上就會被fill, 初始化也是多余的。

            如果確實需要:
            struct X x_default_initialized = X();


            —— allocator
            絕對是需要的。 你用不上不等于別人用不上。

            如果去掉allocator, 當那個默認的allocator不滿足你的需要時,報銷的(不能被復用的)不僅僅是那個默認的allocator, 而是連同整個data structure庫都廢掉。

            而加上allocator并不會引起什么害處。
            別說“vector<int, my_allocator> 和vector<int> 不是同一類型”什么的。
            當你確實需要這種行為時, 他們本來就不應該是一個類型。

            —— auto_ptr和valarray
            不知道這兩位又怎么了。
            是不是boost::scope_ptr比 const std::auto_ptr新潮?
            而在C++加入restrict 之前, valarray都是有用的, 只是你可能用不上而已。



            —— 其他的庫
            只有threading是必須加入語言的。
            因為語言不提供幫助的話, threadding庫是搞不出來的。

            而其他的network, xml, log,就越界了。

            C++不是那些有大公司撐腰的語言, 可以對標準庫肆意的擴充。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-06 17:14
            @溪流
            跟"最小接口"與"人本接口"沒什么關系。
            相對于read_int, read_string, 這兩種設計都可以算是最小接口。


            為了不降低"實現優化的潛力", 保留適當的信息對實現是有用的。
            比如malloc vs calloc。
            用戶端的信息原本是 sizeof(elem) 和 count兩個。
            calloc會將信息繼續帶到下層。
            而malloc將這個信息丟掉了。

            這可能就會影響malloc的某種優化, 比如對齊策略。
            1. 分配12個char的數組
            2. 分配12/sizeof(int)個數組
            對malloc來說, 它接受到的都是12bytes, 已經無法區分這兩者的不同。
            malloc始終返回的是該平臺下有最嚴格對齊的內存。

            而calloc就可以明確知道每個元素的大小, 可以利用這個信息, 計算出該種大小的所有類型在該平臺下的最嚴格對齊需求,就可以少填充一些。

            當然, calloc不一定會使用這個信息進行優化, 但它保有這個優化的潛力。
            (calloc另一個memset的行為就很惡心了)


            而read, 沒想出可以利用size和count進行優化的方法。
            而且將這2個參數分開, 同時又要避免返回時那個除法的話, 還會顯得不夠統一。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-06 16:59
            @溪流
            對, 你說得對。
            fread確實干了多余的事情。

            調用時那個乘法無所謂, 要么就是調用者自己做, 要么就是fread做。
            問題出在返回時那個除法上。 fread總會做一個除法, 對很多情況是不需要的。
            而不使用乘/除法實現的fread又需要大量的循環。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 23:54
            @溪流
            >>那應該告訴我讀了 sizeof(T)/2 個字節,而不是告訴我讀了 0 個 T 啊

            你已經形成思維定勢了:
            1. fread應該設計成什么樣子, 你心中已經有答案
            2. fread如果設計成那樣子我會怎么用, 你已經習慣這么用
            3. 應為我習慣這么用, 所以fread設計成這樣就是不對的

            這是循環論證, 說明不了任何問題。


            現在你要拋棄你的習慣:
            習慣1: 不僅僅用來讀取字節流, 還可以直接讀取二進制格式文件
            習慣2: 有返回值檢測


            然后比較兩段代碼, 看哪段寫著順手:

            void f(T* buf, size_t buf_size, FILE* stream)
            {
            size_t count = fread(buf, sizeof *buf, buf_size, stream);
            for (size_t i=0; i<count; ++i)
            process(buf[i ] );
            }

            void g(T* buf, size_t buf_size, FILE* stream)
            {
            size_t bytes = Read(buf, sizeof(T) * buf_size, stream);
            for (size_t i=0; i< bytes/ sizoef(T); ++i)
            process( buf[i ] );
            }
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 22:05
            @溪流
            讀出半個T怎么辦?
            還沒看懂2樓的代碼?
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 21:08
            @溪流
            你不需要不等于別人不需要……

            你完全將ReadFile或者fread當作"字節流讀取"來使用了。
            實際上,fread不僅僅可以用來讀取字節流;
            還可以用來讀取"二進制格式存放的數據", 比如上面的T。

            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 18:58
            @溪流
            2樓仔細看。 我懶得說了。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 18:36
            @溪流
            你想得太狹隘了。

            仔細看2樓的例子。 T非得是char嗎?
            a非得是數組嗎?

            T a[1]; 可以嗎?
            T v;可以嗎?
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 17:17
            @溪流
            憑什么只能是unsigned char*呢?
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 15:40
            @溪流
            呃。。。 下面不是還要做一次除法么。。。
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 01:00
            @溪流
            下面的READ就是按你說的方式設計的。
            你覺得用著方便嗎?
            re: fread、fwrite 的參數設計問題 OwnWaterloo 2010-04-05 00:45
            fread和fwrite是C標準庫, Read/WriteFile是Windows API。
            如果不需要HANLDE的特殊功能, 使用fread/fwrite的代碼可以不加修改的移植到其他平臺去。

            參數用于錯誤處理。

            T a[count];
            if ( count != fread(a, sizeof a[0], count, stream) ) {
            // error
            }

            if ( count != READ(a, sizeof a, stream )/sizeof a[0] ) {
            // error
            }
            msvc和gcc都有相應的分析工具。
            VS的IDE中有個性能分析工具, 具體是怎么讓cl去完成的不了解。
            而gcc相應的工具是gprof和gcov。 gprof是使用-pg選項,給每個函數添加hook代碼(它是編譯器,當然知道如何添加。。。)
            gcov的選項有點復雜…… 好像是-ftest-coverge什么的。

            只要截獲每次函數調用, 除非是搞什么longjmp或者exit, 調用樹運行時間等東西都可以得到。

            當然, 這不太像log了…… 不過看你的描述, 你需要的功能也不是log了……
            就是程序動態分析工具。
            @cexer
            在我看來恰恰相反, 全局數據與用戶之間的交互形式有若干, 而單件只是其中一種。
            re: 將成員函數作為回調函數 OwnWaterloo 2010-04-03 19:49
            @Sanxcoo
            哈, 既然你已經找了這么復雜的方案, 相信你是清楚tr1::function這種東西是無效的~_~

            tr1::function對象或者std::binder1st, std::bind2nder對象的接受者都是template。
            而當接收者只能接受pointer to function時, tr1::function, binder這種東西都是無效的~


            這里有一個類似的, 不過不需要寫匯編。
            http://code.google.com/p/callback-currying/source/browse/trunk/src/stdcall2stdcall.c

            項目新的地址在
            http://github.com/OwnWaterloo/callback-currying

            不過目前是空的……
            我也這么干過:

            class C{
            C() {
            CoInit()
            }
            ~C() {
            CoUnit()
            }
            ...
            };

            為的也是讓其他代碼干凈一些, 不要引入那些丑陋的頭文件以及看到COM這么丑陋的東西。

            全局數據初始化有不同的設計方法。
            如果內部有引用技術, 就可以這么干。
            如果沒有, 就告訴C的使用者, 使用前需要怎樣, 使用后又怎樣。
            @溪流
            MIT應該不用, 只保原始代碼中的版權申明即可。
            這話說的很不負責啊, 最好還是詳細查一下……
            re: 將成員函數作為回調函數 OwnWaterloo 2010-04-02 15:56
            @陳梓瀚(vczh)
            std::function?
            那是什么東西?
            @cexer
            用于單件的那些技術, 同樣可以用于全局數據初始化。

            C運行庫為你初始化堆分配器, 不也不需要你多余控制?
            進程終結后也會自己終結。
            呃, C庫不一定會真正釋放, 有可能留給OS。
            那換個例子, atexit。

            所以單件根本不是什么偉大的發明。
            只是OO時代的順應產物。
            re: loki技法(1).靜態斷言 OwnWaterloo 2010-04-01 22:57
            《modern c++ design》 是loki作者寫的介紹該庫的書。
            共10頁: 1 2 3 4 5 6 7 8 9 Last 
            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            常用鏈接

            留言簿(8)

            隨筆檔案(16)

            鏈接

            搜索

            •  

            積分與排名

            • 積分 - 198340
            • 排名 - 134

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            久久99这里只有精品国产| 久久久久久久精品妇女99| 久久96国产精品久久久| 99久久久精品免费观看国产| 99久久99久久精品国产片果冻| 国产2021久久精品| 国产精品一区二区久久精品涩爱| 漂亮人妻被黑人久久精品| 国产精品欧美亚洲韩国日本久久| 久久亚洲国产精品成人AV秋霞| 久久青青草原亚洲av无码app | 精品伊人久久大线蕉色首页| 久久久久人妻一区二区三区vr| 久久久久亚洲av成人无码电影| 久久精品夜夜夜夜夜久久| 欧美色综合久久久久久| 99国产精品久久| 7777久久久国产精品消防器材| 国产视频久久| 久久ww精品w免费人成| 精品久久久久久无码国产 | 久久精品国产欧美日韩| 日本久久久久亚洲中字幕| 国产精品亚洲美女久久久| 久久人人爽爽爽人久久久| 一本色道久久99一综合| 久久国产视屏| 狠狠色综合久久久久尤物| 久久精品国产半推半就| 久久精品麻豆日日躁夜夜躁| 久久夜色精品国产欧美乱| 久久久久高潮综合影院| 亚洲欧洲久久av| 久久久国产亚洲精品| 婷婷久久综合九色综合绿巨人| 久久国产精品免费一区二区三区| 97久久香蕉国产线看观看| 99久久er这里只有精品18| 9久久9久久精品| 久久亚洲国产欧洲精品一| 999久久久国产精品|