2016年9月11日
cmake學習(一)靜態庫與動態庫構建
(.so)共享庫,shared object:節省空間,在運行時去連接,如果執行機器上沒有這些庫文件就不能執行。
(.a)靜態庫,archive:靜態庫和程序化為一體,不會分開。
通過 ldd命令可以查看一個可執行程序所依賴的的共享庫。
使用環境變量LD_LIBRARY_DIRECTORY可以指定共享庫位置
一、編譯共享庫:
ADD_LIBRARY(hello SHARED ${SHARED_LIBRARY})
二、添加靜態庫:
ADD_LIBRARY(hello STATIC ${STATIC_LIBRARY})
因為默認規則是不能有相同名字的共享庫與靜態庫,所以當生成靜態庫的時候(so后綴),共享庫會被刪除,因為只能允許一個名字存在,相同名字的會被替代(hello),所以需要通過SET_TARGET_PROPERTIES()來解決這個問題,例子:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
cmake在構建一個target的時候,會刪除之前生成的target,一樣是通過設置SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)來達到目的
三、動態庫的版本號:
同樣是通過SET_TARGET_PROPERTIES()來設置
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION:動態庫版本
SOVERSION:API版本
最后生成的結果是:
libhello.so.1.2
libhello.so.1->libhello.so.1.2
libhello.so->libhello.so.1
四、安裝:
INSTALL(TARGETS hello hello_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
INSTALL(TARGETS hello.h
DESTINATION include/hello)
其他常用的屬性 PERMISSIONS:設置權限;RATTERN:設置正則表達式
Summary:
ADD_LIBRARY():添加一個庫,共享庫,靜態庫,模塊
SET_TARGET_PROPERTIES():設置輸出名稱,版本號,解決相同target被刪除的問題
GET_TARGET_PROEERTIES():與SET功能相對
cmake學習(二)常用變量和常用環境變量
一、變量的引用方式是使用“${}”,在IF中,不需要使用這種方式,直接使用變量名即可
二、自定義變量使用SET(OBJ_NAME xxxx),使用時${OBJ_NAME}
三、cmake的常用變量:
CMAKE_BINARY_DIR,PROJECT_BINARY_DIR,_BINARY_DIR:
這三個變量內容一致,如果是內部編譯,就指的是工程的頂級目錄,如果是外部編譯,指的就是工程編譯發生的目錄。
CMAKE_SOURCE_DIR,PROJECT_SOURCE_DIR,_SOURCE_DIR:
這三個變量內容一致,都指的是工程的頂級目錄。
CMAKE_CURRENT_BINARY_DIR:外部編譯時,指的是target目錄,內部編譯時,指的是頂級目錄
CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt所在的目錄
CMAKE_CURRENT_LIST_DIR:CMakeList.txt的完整路徑
CMAKE_CURRENT_LIST_LINE:當前所在的行
CMAKE_MODULE_PATH:如果工程復雜,可能需要編寫一些cmake模塊,這里通過SET指定這個變量
LIBRARY_OUTPUT_DIR,BINARY_OUTPUT_DIR:庫和可執行的最終存放目錄
PROJECT_NAME:你猜~~
四、cmake中調用環境變量
1.Using $ENV{NAME} : invoke system environment varible.
We can use "SET(ENV{NAME} value)" as well. note that the "ENV" without "$".
2.CMAKE_INCLUDE_CURRENT_DIR equal to INCLUDE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
五、其他的內置變量
1.BUILD_SHARED_LIBS:set the default value when using ADD_LIBRARY()
2.CMAKE_C_FLAGS: set compiler for c language
2.CMAKE_CXX_FLAGS: set compiler for c++ language
六、區分debug和release
在工程目錄下,cmake -DCMAKE__BUILD_TYPE=DEBUG(RELEASE),再執行make
七、指定編譯32bit或64bit程序
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
cmake學習(三)常用指令
一、基本指令:
INCLUDE_DIRECTORIES(${includedir}) #-I。
LINK_DIRECTORIES(${libdir}) #-L
TARGET_LINK_LIBRARIES(helloworld ${linkflags}) #-l
ADD_DEFINITIONS(${cflags}) #-D
1、ADD_DEFINATIONS:向C/CPP添加宏定義,相當于gcc中的-D,參數之間用空格分割
2、ADD_DEPENDICIES(target_name, depend_name):定義target對其他target的依賴關系
3、AUX_SOURCE_DIRECTORY(dir VARIBLE):把目錄下的所有源文件保存在變量中,基本用來創建源文件列表
4、ADD_EXECUTABLE:指定目錄,生成執行文件
5、EXEC_PROGRAM:外部調用指令,可移執行任何外部命令,后面加參數,例子如下:
EXEC_PROGERAM(ls ARGS"*.c" OUTPUT_VARIBLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF(not LS_RVALUE)
MESSAGE(STATUS "xxx")
ENDIF(not LS_RVAULE)
PS.這里執行ls *.c指令,執行成功的話,返回0。
6、FILE指令:
FILE(WRITE file_name "content")
FILE(APPEND file_name "content")
FILE(READ file_name varible)
FILE(WRITE file_name "content")
7、FIND_系列指令:
LIBRARY( name path):
FIND_LIBRARY(Xorg X11 /usr/lib64)
IF(not Xorg)
MESSAGE(STATUS "no Xorg")
ENDIF(not Xorg)
FILE( name path)
PATH( name path)
PROGRAM( name path)
PACKAGE( [major.minor][QUIET][NO MODULE][[REQUIRED][COMPONTS][componts....]])
最后一條,用來調用放在CMAKE_MODULE_PATH下的Find.cmake模塊,也可以自定義Find模塊
首先通過SET(CMAKE_MODULE_PATH /home/...)來指定位置
8、控制指令:
IF(expression),ELSE(expression),ENDIF(expression)
express舉例:
否定:空,0,N,NO,OFF,FALSE,NOTFOUND或_NOTFOUND
肯定:COMMAND cmd,EXISTS dir/file,variable MARCHES regex等等等等還有很多~~~隨用隨查吧
cmake學習(四)模塊的使用和自定義模塊
FIND_PACKAGE
每一個模塊都會產生如下變量
_FOUND
_INCLUDE_DIR
_LIBRARY or _LIBRARIES
如果_FOUND為真,把_INCLUDE_DIR加入到INCLUDE_DIRECTORIES中,_LIBRARY加入到TARGET_LINK_LIBRARIES中。
編寫屬于自己的FindHello模塊:
1.FIND_PATH(HELLO_INCLUDE_DIR hello.h /usr/include/hello /usr/local/include/hello)
2.FIND_LIBRARY(HELLO_LIBRARY_DIR NAMES hello PATH /usr/lib /usr/local/lib)
IF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
SET(HELLO_FOUND TRUE)
ENDIF(HELLO_INCLUDE_DIR)
3.FIND_PACKAGE([major.minor][QUIET][NO_MODULE]
[[REQUIRED|COMPONENTS][componets...]])
QUIET參數:去掉輸出信息
REQUIRED參數:共享庫是否是工程必須的,如果是必須的,那么找不到
如果在src中想調用hello模塊中的內容
FIND_PACKAGE(HELLO)
為了可以讓工程找到FindHELLO.cmake
在主工程的CMakeList.txt中,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_PATH}/cmake)
通過設置FIND_PACKAGE(HELLO QUIET)可以去掉輸出信息
Cmake CMAKE_BUILD_TYPE specification
That’s because no build type has been specified to CMake. The build type is a feature most IDE have, it allows you to compile your program in “debug” mode, for easily single-stepping through it with a debugger, or in “release” mode, with speed optimization enabled.
To fix this you simply need to specify a build type in the CMakeLists.txt file, in this way:
if( NOT CMAKE_BUILD_TYPE )
set( CMAKE_BUILD_TYPE Debug CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo
MinSizeRel."
FORCE )
endif()
when cmake is run without specifying the build type using -D CMAKE_BUILD_TYPE, it is the Debug mode that is selected as the default.
2016年6月28日
SDL是一個輕量級的,用C語言開發的多媒體庫。它包含了圖像繪制、文字繪制、事件處理、聲音播放等模塊。因為SDL的易用以及它的擴展庫的完整性,很多2D游戲都使用SDL開發,其中就包括這幾年大熱的移動平臺上的游戲《憤怒的小鳥》。
然后說說從個人角度上看SDL的特點。
1.跨平臺。確確實實是跨了N個平臺,甚至包括NDS這種平臺。有了SDL,你甚至可以在windows、linux、Android上任意移植你的游戲。當然,前提是你目標平臺的編譯器認識你的代碼( ̄▽ ̄)”。有了SDL泥甚至可以只用c語言開發安卓游戲喲。
2.開源。3.SDL2.0繪圖效率很高。事實上相較之SDL1.2我個人比較喜歡SDL2.0的原因也是在此。個人感覺(其實我沒看過源碼)SDL1.2應該是個跟當年的DirectDraw差不多的東西,像素填充什么的,有相當程度上是要磨CPU的。而SDL2.0從繪圖方式上就革新了,拋棄了之前的surface與clip的模式,把實際繪制的東西改為了Texture,而把之前的surface改為了創建Texture的一個臨時環節。而texure,顧名思義,其實就是DirectX、OpenGL這些底層的3D硬件加速API的貼圖。
當下DirectX、OpenGL標準下的顯卡的渲染管線無非就是:1.把頂點(可以理解成坐標)傳給顯卡 。2.把texture傳給顯卡。 3.告訴顯卡怎么處理這些數據(shader)。 4.顯卡把東西給你顯示出來。而基于DirectX、OpenGL(移動平臺是OpenGL ES)的SDL2.0,正是恰好地利用了當下顯卡的能力。
4.SDL可以用作3D圖像引擎和底層DirectX/OpenGL API的中間層。當然,其實如果把SDL這樣用的話,那就真是很薄的一層了:)
5.易用。這是相對而言的,比如在windows上,你用了SDL這個庫之后,基本就不用去理會Windows那些又臭又長用不著的參數又多的API了。我不是在討論信仰問題也不是要詆毀windows,我是在客觀陳述windows api那個要初始化一個窗口必須要堆100行代碼的設定實在是打擊初學者積極性的事實。
SDL_image、SDL_ttf、SDL_mixer、SDL_net 外部擴展庫,也是不錯的選擇。性能沒有測試,僅從寫代碼角度上來說,個人感覺2.0將操作給弄得復雜了。
1.2---------------------------------------
只有SDL_Surface的概念,屏幕是surface,圖片,文字等都是surface,
只要將準備好的各種圖片,貼到屏幕里去(SDL_BlitSurface);再刷一下屏幕(SDL_Flip全局的、或SDL_UpdateRect局部的)就ok了。。。
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_Surface* bmp = SDL_LoadBMP("back.bmp");
SDL_BlitSurface(bmp, 0, screen, 0);
SDL_Flip(screen);
while(SDL_WaitEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
return;
}
}
SDL_Quit();
2.0---------------------------------------
整出了SDL_Window,SDL_Renderer,SDL_Texture新的3個東西。
并且我要畫一張圖,先要得到surface,然后轉換為texture,再臨時貼到renderer,最后才刷屏。
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow("hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Surface* surface = SDL_LoadBMP("back.bmp");
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, 0, 0);
SDL_RenderPresent(renderer);
while(SDL_WaitEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
return;
}
}
SDL_Quit();
其實,我真心不覺得提出SDL_Window,SDL_Renderer,SDL_Texture這些概念先進性在哪里?可能是與openGL的概念保持一致吧。
而且從維護的角度出發,不管sdl2.0性能提升了多少,如果接口本身不需要改動,不是更加好么?
---------------------------------------------
最后我發現,同樣是渲染的窗口
1.2用SDL_Flip(screen);之后被其他窗口擋住之后,回來畫面還是在的;
2.0用SDL_RenderPresent(renderer);之后被其他窗口擋住之后,回來畫面就不在了;
2015年12月6日
摘要: OpenCV從1.0到現在的3.0,變化還是相當大的。大趨勢是從C結構層次到C++類層次的轉變。先從OpenCV底層的圖像數據結構談起,1.0時 圖像數據結構是IplImage,之后是cvmat,之后2.2中出現了CvvImage,之后就是cv::mat,2.3之后CvvImage就被廢棄了。
opencv中對圖像的處理是最基本的操作,一般的圖像類型為Ipl...
閱讀全文
2015年3月17日
摘要: 問題:Update字段來自子查詢或者來自其他表字段
Update 語句
Update 語句用于修改表中的數據。
語法:UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值SQL update select語句
最常用的update語法是:
UPDATE <table_name> SET <column_name1> = <value&...
閱讀全文
2014年8月22日
永遠不要用#include包含不必要的頭文件
如果只需要流的前置聲明,應該優先使用#include<iosfwd>
只需要前置聲明時,絕不要用#include包含相應的頭文件。
如果使用聚合關系就已經足夠,就不要使用繼承。
要避免使用內聯或者復雜的調整方法,除非通過性能分析證明這確實是必要的。
正確使用名字空間。如果將一個類放入名字空間,那么同時要保證將這個類的所有輔助函數和運算符函數也放入相同的名字空間。否則,你將在代碼中發現奇怪的結果。

要理解這五種不同類型的內存,了解他們為什么是不同的,以及他們各自的行為又是怎么樣:棧(自動變量)、自由存儲(new/delete)、堆(malloc/free)、全局(靜態變量、全局變量、文件作用域變量等)、常量數據(字符串常量等)。
優先使用自由存儲(new/delete),避免使用堆(malloc/free)。
對于“堆”和“自由存儲”進行區分,這一點很重要,因為在C++標準中有意避開了這兩種類型的內存是不是相關的這個問題。例如,當通過::operator delete()函數來釋放內存時,在C++標準的18.4.1.1中,最后一項是這樣的:
“ 在C++標準中并沒有規定,在哪些情況下,在通過operator delete回收的存儲空間中,有一部分或者全部的控件可以再隨后調用operator new或者calloc,malloc以及realloc等函數時被重新分配,這些函數的聲明時在<cstdlib>中。”
而且,在C++標準中也沒有規定,new/delete是否需要通過malloc/free來實現。不過,在C++標準20.4.6節的第3段和第4段中規定了,malloc/free一定不能使用new/delete來實現:“calloc、malloc和realloc函數不會通過調用::operator new()來分配存儲空間。函數free()不會通過調用::operator delete() 來釋放內存。”
如果在類中定義了new和delete中的任意一個運算符函數,那么一定要同時定義另外一個。
通常應該顯式地將函數operator new ()和operator delete()聲明為靜態函數。他們永遠都不能使非靜態成員函數。
永遠都不要通過多態的方式處理數組。
優先選擇使用vector或者deque,而不是數組。
在編寫拷貝賦值運算符函數時,永遠都不要指望能夠通過對自我賦值進行檢測來保證函數的正確性;應該在拷貝賦值運算符函數中使用“創建臨時對象并進行交換”的慣用法,這種方法不僅是異常安全的,而且在處理自我賦值時也是安全的。
可以將自我賦值檢測作為一種優化手段,以避免不必要的工作,這是正確地做法。
不僅要避免編寫類型轉換運算符函數,而且還要避免編寫隱式的構造函數。
盡量編寫異常安全的代碼。在編寫代碼時應該始終遵循:即使在出現異常時,資源仍然能夠被正確地釋放,并且數據也總是處于一致的狀態。
避免使用語言中那些不常用的特性,而應該使用最簡單并且有效的技術。
拷貝初始化過程絕不是賦值過程,因此在初始化中永遠都不會調用函數T::operator=()。是的,我知道在初始化語句中有一個“=”符合,但不要被它迷惑。它只是從C語言中沿用過來的一種語法,并不代表賦值運算。
如果可能的話,優先使用“T t(u);”這種形式,而不是“T t=u;”的形式。通常,能能夠時候后者的地方,都可以使用前者,并且使用前者還有更多的好處——例如,可以帶多個參數。
在函數聲明中,如果參數是以傳值方式來傳遞的,則不要使用const。而如果在這個函數的定義中,參數是不能被修改的,那么應該使用const。
對于不是內置類型的返回值來說,當使用返回值的方式而不是返回引用的方式時,應該優先選擇返回const值。
const 和mutable都是你的朋友
優先使用新形式的類型轉換。
不要通過類型轉換去掉常量屬性,而應該使用mutable。
避免使用向下的類型轉換。
優先通過引用方式來傳遞對象參數,而不是傳值方式,并且在所有可能的地方都使用const。
避免使用內聯,除非從性能的分析上來看確實有必要這么做。
避免使用全局變量或者靜態變量。如果必須使用,那么一定要特別注意這些變量的初始化順序。
在構造函數的初始化列表中,應該把 基類按照他們在類定義中出現的先后順序進行排列。
在編寫代碼時,永遠都不應該依賴函數參數的求值順序
絕對不要對無效的迭代器執行解引用(dereference)操作
用于不要將異常安全性放在事后考慮。異常安全性會影響到類的設計。它永遠都不會“只是一個實現細節”。
在傳遞對象參數時,選擇const&方式而不是傳值方式。
對于程序運行中不會改變的值,應該預先計算并保存起來備用,而不是重復地創建對象,這是沒有必要的。
通常,為了保持一致性,應該使用前置遞增來實現后置遞增,否則,當其他用戶在使用你的類時,可能會得到奇怪結果。
優先選擇使用前置遞增。只有在需要初始值時,才使用后置遞增。
在進行隱式類型轉換時,要注意在轉換過程中創建的 臨時對象。要避免這個問題,一個好辦法就是盡可能地通過顯式的方式來構造對象,并避免編寫類型轉換運算符。
記住對象的生存期。永遠,永遠,永遠都不要返回指向局部對象的指針或引用;它們沒有任何用處,因為主調代碼無法跟蹤它們的有效性,但卻可能會試圖這么做。
盡可能地重用代碼——尤其是標準庫中的代碼——而不是自己去編寫代碼,這樣更快、更容易,也更安全。
如果在函數中不打算處理所拋出的異常,那么應該將異常轉發給能夠進行處理的上層調用者。
在編寫代碼時應該始終遵循:即使在出現異常時,資源仍然能夠被正確地釋放,并且數據也總是處于一致的狀態。
遵循標準的異常安全規則:永遠不要在析構函數、重載運算符函數operator delete()或者operator delete[]()中拋出異常; 在編寫每個析構函數和內存釋放函數時,要假設存在著“throw()”這樣的異常規范。
遵循標準的異常安全性規則:在每個函數中,要將所有可能會拋出異常的代碼單獨放在一起,并且對這些代碼進行安全處理。然后,當你確認這些代碼執行的工作都已經成功地完成時,才可以使用不會拋出異常的操作來修改程序的狀態。
永遠都不要到最后才實現異常安全性。異常安全性會對類的設計產生影響。它永遠都不會“只是一個實現細節”。
優先考慮實現內聚。要努力使每段代碼——每個模塊、每個類、每個函數——都只有單一的,并且是明確定義的功能。
“異常不安全”總是與“拙劣的設計”結伴的。如果程序的設計邏輯清晰,那么即使有一段代碼不是異常安全的,一般來說也不會有太大問題,并且可以很簡單地進行修正。但如果有一段代碼由于設計問題而不能被編寫成異常安全的,我們通常都會認為這個設計時拙劣的。下面是兩個拙劣設計的示例。
示例1:如果在一個函數中需要實現兩個不同的功能,那么這個函數很難被編寫成異常安全的。
示例2:如果在拷貝賦值運算符函數中必須對自我賦值進行檢測,那么這個函數也可能不是完全異常安全的
遵循標準的異常安全性規則:以“獲得資源也就意味著初始化”這種模式來分離資源的所有權和資源的管理權。
在進行設計中,要始終牢記重用性。
優先采用“ a op=b;”這種寫法,而不是"a = a op b;"(這里的op表示某個運算符)。這種寫法更為清晰,效率也高。
如果定義了某個運算符(例如,operator+),那么通常還應該同時定義與這個運算符相對應的賦值運算符(例如,operator+=)。并且用后者來實現前者。而且,還應該維護op和op=之間的自然關系。
在C++標準中規定:運算符=,(),[]和->必須被定義為成員函數,而在類中定義的new,new [],delete和delete[]等運算符函數必須是靜態成員函數。對于其他的運算符函數:
如果運算符函數是用于流I/O的opeator>>或者operator<<,或者如果運算符函數需要對其左操作數進行類型轉換,或者運算符函數可以通過類的公有接口來實現,那么將這個函數定義為非成員函數(在前兩種情況中,如果需要的話也可以被定義為友元函數);如果運算符函數需要實現虛函數的行為,那么增加一個虛函數來提供虛函數的行為,并用這個虛成員函數來實現運算符函數否則將預算富函數定義為成員函數。
在函數opeator>>和operator<<中應該始終返回對流對象的引用。
將基類的析構函數定義為虛函數(除非你能保證,永遠都不會有人通過指向基類的指針來刪除派生類的對象)。
如果在派生類中定義的函數與基類中的函數有相同的名字,并且你不想隱藏基類中函數,那么應通過using聲明語句將基類的這個函數引入到派生類的作用域中。
永遠不要改變被覆蓋的基類函數中的默認參數值。
除了對真正的Liskov IS-A和WORKS-LIKE-A關系進行建模之外,永遠都不要使用共有繼承。所有被覆蓋的成員函數不能超過實際需求的范圍,同時也不能小于這個范圍。
使用公有繼承的目的是重用代碼(編寫以多態的方式使用基類對象的代碼),而重用(基類中的)代碼并不一定要使用公有繼承。
對“is implemented in terms of”這種關系建模時,應該優先選擇成員關系/包含的方式,而不是私有繼承的方式。只有非用繼承不可時,才應該使用私有繼承——也就是說,當需要訪問保護成員或者需要覆蓋虛函數時,才使用私有繼承。永遠都不要只是為了代碼重用而使用共有繼承。
對于廣泛使用的類,應該優先使用編譯器防火墻這種慣用法(也叫做Pimpl慣用法)來隱藏實現細節,通過一個不透明的指針(指向一個進行了前置聲明但又沒有定義的類)來保存私有成員(包括狀態變量和成員函數),聲明這個指針時可采用“struct XxxxImpl* pImpl;XxxxImpl* pimpl_;”這樣的形式。例如:“class map{ private :struct MapImpl;MapImpl* pimpl_;}”
包含,也可以叫做“聚合”,“分層”,“HAS-A”或者“委托”。優先選擇包含而不是繼承,對于IS-IMPLEMENTED-IN-TERMS-OF這種關系建模時,應該優先考慮使用包含,而不是繼承。
2014年7月24日
2014年6月25日
1.確保目標空間足夠大
2.了解各種與排序有關的選擇
如果需要對vector、string、deque或者數組中的元素執行一次完全排序,那么可以使用sort或者stable_sort。
如果有一個vector、string、deque或者數組,并且只需要對等價性最前面的n個元素進行排序,那么可以使用partial_sort。
如果有一個vector、string、deque或者數組,并且需要找到第n個位置上的元素,或者,需要找到等價性最前面的n個元素但又不必對這n個元素進行排序,那么,nth_element正是你所需要的函數。
如果需要將一個標準序列容器中的元素按照是否滿足某個特定的條件區分開來,那么,partition和stable_partition可能正是你所需要的。
如果你的數據在一個list中,那么你仍然可以直接調用partition和stable_partition算法;可以用list::sort來替代sort和stable_sort算法。但是,如果你需要獲得partial_sort或nth_element算法的效果,那么,正如前面我所提到的那樣,你可以有一些簡潔的途徑來完成這項任務。
3。如果確實需要刪除元素,則需要在remove這一類算法之后調用erase。
remove不是真正意義上的刪除,因為它做不到。
4.對包含指針的容器使用remove這一類算法時要特別小心。會導致資源泄露。
5.了解哪些算法要求使用排序的區間作為參數。
6.通過mismatch或lexicographical_compare實現簡單地忽略大小寫的字符串比較
7.理解copy_if算法的正確實現
8.使用accumlate或者for_each進行區間統計。
2014年6月13日
1.iterator 優先于const_iterator、reverse_iterator及const_reverse_iterator
2.使用distance和advace將容器的const_iterator轉換成iterator
3.正確理解由reverse_iterator的base()成員函數所產生的iterator的用法。
4.對于逐個字符的輸入請考慮使用istreambuf_iterator
2014年5月16日
1.理解相等(equality)和等價(equivalence)的區別
相等的概念是基于operator==的。等價關系是以“在已排序的區間中對象值得相對順序”為基礎的。如果從每個標準關聯容器的排列順序來考慮等價關系,那么著將是有意義的。標準關聯容器室基于等價而不是相等的。標準關聯容器總是保持排列順序的,所以每個容器必須有一個比較函數(默認less)來決定保持怎樣的順序。等價是按照比較函數子。因此,標準關聯容器的使用者要為所使用的每個容器指定一個比較函數(用來決定如何排序)。如果該關聯容器使用相等來決定兩個對象是否有相同的值,那么每個關聯容器除了用于排序的比較函數外,還需要另一個比較函數來決定兩個值是否相等(默認情況下,該比較函數應該是equal_to,但有趣的是equal_to從來沒有被用做STL的默認比較函數。當STL中需要相等判斷時,一般的慣例是直接調用operator==。比如,非成員函數find算法就是這么做的)
2.為包含指針的關聯容器指定比較類型
why?第一條已經說明關聯容器是要排序。每當你要創建包含指針的關聯容器時,一定要記住,容器將會按照指針的值進行排序。一般是不是你希望的,所以你幾乎要創建自己的函數子類作為該容器的比較類型。
3.總是讓比較函數在等值情況下返回false
比較函數的返回值表明的是按照該函數定義的排列順序,一個值是否在另一個之前。相等的值從來不會有前后順序關系,所以,對于相等的值,比較函數應該始終返回false。
4.切勿直接修改set或multiset中的鍵。
5。考慮用排序的vector替代關聯容器
在排序的vector中存儲數據可能比在標準關聯容器中存儲同樣的數據要耗費更少的內存,而考慮到頁面錯誤的因素,通過二分搜索法來查找一個排序的vector可能比查找一個標準關聯容器要更快一些。
6.當效率至關重要時,請在map::operator[]與map::insert之間謹慎做出選擇
map::operator[]的設計目的是為了提供“添加和更新”的功能。添加一個新元素最好選后者insert。
7.熟悉非標準的散列容器。