re: 蓋莫游戲引擎2.1.0發布了[未登錄] Dancefire 2010-06-30 09:18
建議在google code hosting上建立一個開源項目,這樣發布、源代碼下載修改,bug提交都會比較容易。
re: 2個c++編譯器的差異[未登錄] Dancefire 2010-06-30 09:14
@ccsdu2009
如果是Dev-c++那就更慘了。Dev-C++已經5年沒有更新過了。其中的gcc版本也是甚老的版本,3.4.2。能嘗試著用mingw gcc 4.x以上編譯一下看看么?
http://tdm-gcc.tdragon.net/ 有非官方的gcc 4.4的安裝包。
re: 2個c++編譯器的差異[未登錄] Dancefire 2010-06-26 20:49
請檢查一下你現在使用的mingw的版本。mingw當前的穩定版本是4.5.0-1。但是如果你通過mingw的windows自動安裝程序(已不推薦使用) 5.1.6來安裝的話,會安裝3.4.5。目前比較正確的使用mingw的方法應該是下載壓縮包自己解壓縮到合適的位置。下一代的自動安裝程序mingw-get剛剛進入alpha測試階段,如果嘗試也可。
說這些的原因是提醒注意是否是由于gcc 3.x和4.x的差異導致的不同。如果是的話,那么只需要安裝最新的mingw的編譯器即可,不必調整代碼。
我的觀點是這樣:
1、如果只有5層左右if嵌套,不是什么大問題。可以用一個函數解決,看到不少代碼中都是存在一個函數中有多層if嵌套。
2、如果嵌套太多,影響函數邏輯的清晰了。那么拆解函數,將功能獨立的內層嵌套,拆解成獨立的函數。保證每個函數中嵌套不要太多,而拆解出的函數,功能又比較獨立。
3、對于需要重復寫每次清理時繁瑣的步驟的問題,如果確實重復、確實繁瑣,可寫成一個函數,每次清理前調用一下這個函數即可。不用擔心調用成本,C++會自動分析,編譯Release版本時,很有可能會將其視為inline。
4、假如Process和Token的每次創建過程都比較復雜,比如有多種情況要考慮,多種錯誤要處理,出現問題后要有多種錯誤處理方式。那么建議將Process和/或Token進行類封裝。這樣使用時,只要Process p;即可,發現錯誤直接return false; p會自動析構,調用相應的析構函數來清理垃圾。在這種情況下,我與第一個回復的朋友觀點一致。不要擔心類的成本,只要沒有繼承、虛函數之類的東西,類的效率與調用函數無太大差別。
5、使用異常。異常的設計初衷本就是為了解決這種現象的,避免錯誤處理影響了函數邏輯。如果出了錯就是異常處理、清理、返回,而不會出現改正錯誤重新執行代碼的情況,可以使用異常。這樣只要出錯就拋出異常,不同的錯誤,異常不同。函數內解決異常,不讓異常出函數。這樣也可以將錯誤處理集中起來。
如果我沒有理解錯,你試圖用locale為ASCII的isspace來判斷GBK編碼的空格,對么?如果我理解正確的話,那么這不是VC的問題,而是使用上的問題。
對于C++而言,應該使用isspace(ch, loc); 這個版本,loc是類型為std::locale的變量,如果你想判斷GBK的空格,那么讓loc是GBK的locale,然后這個函數就正常了。
你現在使用的是C的isspace(ch)函數,這個函數使用的是默認的全局locale,你把這個全局的設為GBK,也應該可以解決這個問題。總之調用locale為默認的ASCII的locale的isspace去判斷編碼為GBK的字串是否是空格,邏輯上不對。
re: 我的項目Makefile文件模板 Dancefire 2009-02-25 00:23
樓主,對于幾個源代碼的文件,可以考慮直接用Makefile寫寫。但是對于真正的項目,用Makefile就遠遠不足了。建議樓主了解一下三個工具,autotools、CMake、SCons。使用這些工具,對于你寫的這50行左右的Makefile,甚至可能可以縮減為不超過5-10行。
autotools,包括automake, autoconf之類的工具。它能夠自動生成Makefile。是比較早期的Makefile替代物(Makefile不叫早期,叫原始)。不難用,很多開源軟件都用它。
CMake和SCons是比較現代點的工具。相比而言,我更推薦CMake。
CMake可以跨平臺,它并不直接build,而是先生成平臺上習慣的Build文件,然后再用平臺自己的工具進行Build。比如在Linux上,它可以先生成Makefile,然后用戶直接make就可以了。而在Windows上,它可以直接生成Visual Studio的項目文件,然后用戶可以用VS打開其文件進行Build。這種方式我比較喜歡,而且使用起來也非常的簡單。
SCons是基于Python的,甚至配置也是,強大之處在于如果你會Python,那么可以在里面做任何事,畢竟這比automake或者makefile的shell強大太多了。但是缺陷是許久沒有發展了,主要在bugfix中。而且通過google trends比較可以看出CMake比SCons似乎更有活力,發展更好。
@volnet
Boost可以稱其為是一套準標準庫。它項目建立的目的之一就是為未來的C++標準庫提供候選方案,目前已經有將近十個Boost庫成功的成為了C++標準預案。
它的優勢很多,首先是代碼使用現代C++的語法,因此namespace, 異常, 模板之類的C++特性會被充分挖掘利用,代碼從設計、實現到文檔都具有了相當高的水準。另外,由于它使用的是標準C++語法編寫,因此它的可移植性非常的好。當然,針對一些存在問題的編譯器,它也會進行相應的調整以盡量支持。
Boost這種優良的庫,涵蓋的領域很廣,可以說是標準庫很好的補充。另外絕大多數Boost庫都不需要編譯鏈接,大部分的Boost庫僅僅include頭文件即可工作。我看到國內很多人提到Boost的時候說它比較難以編譯安裝云云。其實沒必要編譯,絕大多數的庫僅僅是由頭文件組成的,只要include進來就可以用了。
Boost是C++強有力的工具,學習C++,除了標準語法和STL外,Boost是必須熟悉的,否則,工程上很有可能會做一些Boost已經實現很久的東西,除了重復開發外,而且你的代碼的質量和可持續性比Boost差很遠,造成項目質量的下降。
@volnet
呵呵,非模板類型的函數定義我們也不會需要在foo.h中include foo.cpp啊:)
在樓主的例子里面為了能夠讓定義和聲明分開,將聲明放到了foo.h中,而定義放到了foo.cpp中,這和非模板類型的函數是一樣的。但是可惜這么做是無法通過的,因為模板類型函數不能夠(由于沒有export支持)單獨編譯。為了讓編譯通過,樓主將foo.cpp給include進了foo.h,這樣實際上是將兩個文件整合成一個文件了。這樣編譯就沒有問題了,但是得小心需要把foo.cpp分離出項目,因為它不可以被編譯;或者將其擴展名從.cpp改為.hpp。
實在是不推薦樓主這么分開的寫,說實話這算不上是什么標準的做法,而且這樣并沒有太大的意義。如果非要分開,可以將定義后綴到聲明后面,在一個文件里。但是分開確實沒太大意義。可以研讀一下boost里面的做法。
樓主,你的問題其實很簡單。
你是不是把foo.cpp也放進Visual C++的項目里了?如果是的話,這樣會導致foo.cpp的編譯,這個編譯會導致T Foo<T>::GetInstance(void)被編譯實現。當繼續編譯main.cpp的時候,就會報告,T Foo<T>::GetInstance(void)已經有一個實例了。
解決辦法很簡單,把foo.cpp移出工程就可以了。只要物理上foo.h的同目錄存在foo.cpp這個文件就可以了。因為foo.cpp根本沒必要去編譯。甚至我都不建議你稱其為foo.cpp,不如叫什么foo_impl.hpp之類的文件名更合理些,這樣即使這個文件在工程里面也不回導致被編譯。
re: 解決TSVN的diff顯示中文件不全的問題 Dancefire 2009-02-16 11:12
@金慶
嗯,凡是存在非ASCII編碼的字符,都應該采用UTF-8進行文件存儲。如果不使用UTF8,那么意味著使用的是系統本地編碼,在Unicode誕生前,全球那么多種稀奇古怪的編碼,僅僅中文,就有GB2312, GBK, GB10830, BIG5, HZ, Shift-JIS等許多編碼,Subversion之類的軟件根本無法猜測開發人員的機器是什么編碼的,自然會出現亂碼。即使像瀏覽器一樣也來猜測也是不大可能的。Unicode/utf-8是一個非常好的解決這類亂碼問題的解決方案。所以,大部分的這類軟件都做到支持UTF-8,這樣就可以支持全球語言了。
re: 解決TSVN的diff顯示中文件不全的問題 Dancefire 2009-02-15 13:49
@LOGOS
這沒有什么一般不一般的,你保存成utf8就是utf8的。保存文件的時候有一個高級保存選項,你可以選擇是否使用UTF8 with signature來保存。如果代碼中有非ASCII,我一般選擇這個。只要是UTF8的,放到哪里都正常,包括TortoiseSVN的差異和比較。
re: 解決TSVN的diff顯示中文件不全的問題 Dancefire 2009-02-15 00:03
我用TortoiseSVN好像沒有這種問題,你的源文件是使用的UTF-8 with BOM么?如果沒有使用UTF-8 with BOM,可能會出現亂碼的問題,這應該可以理解。
re: Thread Class Dancefire 2009-02-08 22:53
封裝這個作甚?是自己玩么?如果真用起來,還是建議你考慮一下很多已經作好的封裝。許多出色的線程庫都充分利用了C++特性,并且是跨平臺的,比這個要好的多。比如,
[boost::thread]
http://www.boost.org/doc/libs/1_37_0/doc/html/thread.htmlhttp://www.stlchina.org/twiki/bin/view.pl/Main/BoostThread如果需要小巧,也有ting,也是跨平臺的:
[ting]
http://code.google.com/p/ting/也有含在glibmm里面的Glib::Thread
[glibmm/threads]
http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/group__Threads.html如果不是coding 4 fun,而是有任何使用價值,不妨停止重復造輪子,看看已有實現先。畢竟那些充分利用了C++特性,而且是跨平臺的。另外需要注意的是,C++并不追求代碼行數最少,而是追求效率和結構,不要陷入用最短的代碼就是最好的誤區。
樓主,auto_ptr<char> VersionInfo(new char[xx]);的用法絕對是錯的。auto_ptr只會delete指針,而不會delete[]指針。因此VersionInfo的指針不會被釋放。
針對這個問題C++09引入了一個新的庫,scoped_ptr和scoped_array來替代補充auto_ptr。scoped_array就是可以處理數組的。樓主或者下載微軟的2008 feature pack,或者使用boost庫,就可以使用這種智能指針了。除此以外,標準還引入了引用計數型指針,如shared_ptr和shared_array。來處理超出函數范圍的指針釋放問題。樓主可google相關資料。
re: 也談表達式分析和計算 Dancefire 2009-02-05 15:14
@空明流轉
這是我的失誤。復習了一下,BNF應該是可以構建無歧義的語法(
http://www.garshol.priv.no/download/text/bnf.html)。而EBNF構建的語法是可能出現歧義的,而且目前好像沒有算法可以證明EBNF定義的語法是否是無歧義的。(
http://infolab.stanford.edu/~ullman/ialc.html)。但是EBNF肯定是可以構建無歧義的語法的。
發生歧義的時候,boost::spirit可能是按照其實現解析,可能不會報錯也不會列舉多種可能,具體上可以查看boost::spirit的實現,看看它是如何處理這類問題的。
re: 相似圖像搜索(算法) [原創] Dancefire 2009-02-04 19:19
算法上很奇怪,求每一個塊的顏色數的差。首先是無法處理經過縮放的圖片,其次是無法處理整體調暗或調亮或者轉色的圖片,而且求的是平均值而不是常用的SSE?
為什么不考慮用離散余弦求出最顯著的特征,縮小至特定大小后,使用HSV(而不是RGB)來分通道比較并且綜合其結果呢?這樣起碼轉色、縮放、JPG按照不同質量保存或者換圖像格式、調明暗之類的問題基本上都可以處理的。
可以看一些關于模式識別、數據挖掘和圖像處理的書,應該對上述問題都有介紹。
re: 也談表達式分析和計算 Dancefire 2009-02-04 19:01
@陳梓瀚(vczh)
這倒不是Spirit的問題,Spirit實現的是EBNF,BNF(EBNF)不可以處理有歧義的語法。其實很容易理解,BNF是用于編譯程序代碼的,程序代碼是不允許出現歧義的,不然編譯器將無法解析正確結果了。
你說的歧義問題,是處理自然語言中經常碰到的情況,可以對所有可能構成生成一個有向無環圖,然后用概率預測最可能的通路。
@王博煒
那可得多了解了。Boost是C++程序員必備技能之一。Boost的組織內有很多都是C++委員會的成員,庫的內容涵蓋了程序設計的方方面面,雖然不完全,但是很多東西都用得到。而且Boost完全按照C++標準撰寫代碼,它是跨平臺的,基于Boost的代碼,可以很方面的移植到其他系統。另外Boost基本全部由頭文件組成,因此絕大多數庫都不需要鏈接任何東西,直接include到源文件就可使用。Boost內包含了很多成員庫,其質量相當高。從網絡通訊、序列化、線程到正則表達式、內存管理、圖像處理、算法等等,很多東西都可以使用boost來簡化設計。
re: 對基本類型的再包裝,方便了移植 Dancefire 2009-02-04 09:48
@夢在天涯
不是自定義的UInt32,而是標準中的uint32_t或者,int32_t之類。自定義的類型是無法保證這一點的。
是否使用這類確保跨平臺一致性的類型,關鍵在于你的應用在使用這些類型的時候是否關注其大小。比如你僅僅是進行個for-loop,或者簡單的計數或者確定數字不是很大的計算,那自然無所謂了。
但是比如你要把一個數字以二進制格式存儲到硬盤上,或者要進行網絡通訊,其內容是某結構體等,或者某些變量需要至少多少位的空間才能夠滿足需求。碰到這類比較關心實際占用空間大小的問題,而且系統是跨平臺的,那么就需要考慮使用標準中具有跨平臺一致性的類型了。那些是由編譯器會保證跨平臺大小一致的。
re: std::map于vc6下的使用bug Dancefire 2009-02-03 14:07
goodname說的對,凡是形如 xxx<xxx<xxx>>這種模板嵌套的情況,c++當前的標準對此會報錯,因為>>解析的問題。當前的解決辦法是在兩個相鄰的>>之間添加一個空格。
C++09已經修復了這個問題,在今年即將公布的新標準中,你這樣定義是沒有任何問題的。不同的編譯器有不同的處理。自從C++委員會主席加入vc團隊后,vc一直在標準兼容上處于領先地位。特別是c++/cli,允許上述寫法,C++自然也繼承了這個特性,所以你在vs2005下編譯有可能通過。當然vc6這種老掉牙的東西是不支持的。
但是你不應該以是否編譯通過為撰寫代碼的衡量標準,應該按照標準兼容的方式寫代碼。因此目前而言,為了兼容C++標準,你應該在兩個大于號之間加空格,以保證這段代碼可以在其它編譯器下可以工作。
re: 對基本類型的再包裝,方便了移植 Dancefire 2009-02-03 12:56
@true
那就不使用第三方庫好了。boost的頭文件可以直接拷過來用,修改一下當成自己的,算不得第三方庫了吧?或者從mingw中把stdint.h拷過來也行,那個是針對win32平臺修改過的stdint.h。就一個頭文件而已,也算不得第三方庫吧?對于這個頭文件而言,VC6是肯定兼容的,最多稍微修改一下不會太費力氣。
對于類型而言,應該使用標準所制定的跨平臺一致性類型。但是vc不支持,因為我們添加個頭文件讓其支持標準。這樣就可以保證和所有支持c99系統的一致性了。比如linux,甚至freebsd或者netbsd,或者darwin/macos。
所以,在已存在標準這個前提下,那么問題應該描述為如何為vc補全所需標準的內容。這很簡單,遵循標準定義,或者直接那別人已經定義好的頭文件過來就ok了。也不依賴任何第三方庫。
關于你說的__VA_ARGS__,也是C99標準的一部分,所有支持c99的編譯器都支持,包括gcc。
http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.htmlVC2005開始以后都支持了。
http://msdn.microsoft.com/en-us/library/ms177415(VS.80).aspx
因此之前的版本如果不支持,那應該設法為vc6定義一個__VA_ARGS__的宏,來使之支持相應的標準。
原則就是,凡是在標準中已經明確定義的東西,那么誰不支持標準,就讓誰符合標準。而不要自己重復造輪子,因為你無法保證你定義的類型在多系統下兼容,畢竟你接觸和使用的系統有限。何不只讓不符合標準的符合標準,至于其他支持標準的系統,自然不用你來操心。
re: 對基本類型的再包裝,方便了移植 Dancefire 2009-02-03 12:00
@true
我的回復中已經提到,因為微軟尚不支持c99標準,因此vc用戶享受標準提供的便利會有些麻煩。
但是我也提到了,<cstdint>已經被提到TR1并且進而提到了c++09標準中了,因此,各大編譯器已經都開始支持<cstdint>了。對于gcc用戶自然沒問題。對于vc用戶,有很多
種辦法可以提前使用c++09的一些庫:
1) 下載微軟vc2008 Feature Pack,里面提供了TR1的實現,其中包含我提到的頭文件。
2) 更簡單一些,安裝boost,使用<boost/cstdint.hpp>文件,里面也是按照TR1標準/c99標準實現的跨平臺統一的類型文件。
3) 使用第三方的c++標準庫,如apache的stdcxx,里面也基本上支持了TR1,包含了我說的頭文件。
因此完全不用自己定義。更何況自己定義的很難符合跨cpu,跨系統的統一性。而我說的這些實現,由于按照標準,已經支持幾十種系統和cpu的組合了,為什么還要自己定義呢?拿來用就好了。
如果僅僅是擔心vc和其它環境不兼容,那大不了從mingw中把stdint.h拷過來,然后按照vc環境改一改就可以了。這樣在vc環境下include這個頭文件,其它環境下使用標準頭文件。除了微軟外的編譯器基本上都支持c99,因此不用擔心其他平臺的兼容性。
re: 對基本類型的再包裝,方便了移植 Dancefire 2009-02-02 21:18
在1999年以前,你這么做是合理的。但是1999年C99標準推出以后,這樣做就已經不合理了。你應該使用C99的標準頭文件<stdint.h>,如果是C++的話,應該使用<cstdint>。
在stdint.h中,標準明確要求定義:
int8_t;
int16_t;
int32_t;
int64_t;
和
uint8_t;
uint16_t;
uint32_t;
uint64_t;
有關C99的stdint.h的信息請參考wikipedia上的介紹:
http://en.wikipedia.org/wiki/Stdint.hhttp://www.opengroup.org/onlinepubs/009695399/basedefs/stdint.h.htmlc++委員會已經把cstdint納入TR1中,并已經列入c++09的標準中,今年內就會稱為c++標準的一部分。
這些類型的定義,將有所用的編譯器和庫保證其平臺間一致性。gcc和unix下很多C或者C++編譯器的用戶已經隨時可以使用<stdint.h>或者<cstdint>,因為gcc支持c99標準,并且libstdc++也包含了<cstdint>。至于Windows用戶而言,稍有不幸,因為微軟的編譯器不支持c99標準,所以沒有<stdint.h>這個文件,這也可能是樓主不知道這個文件的主要原因。但是沒關系,boost庫提供了tr1的完整實現,其中自然包含了<cstdint>,只要引入<boost/cstdint.hpp>就可以使用上述類型而不用擔心跨平臺性。當然,一如既往,boost提供了更多的可移植性基礎類型的定義。
http://www.boost.org/doc/libs/1_37_0/libs/integer/cstdint.htm請樓主參考這些信息修改文章,畢竟在標準可用下,使用標準更合理。