CPP 學習筆記 可以直接下載pdf CPP 學習筆記 0.1. 多線程 0.1.1. 文件操作已經學完,今天看下多線程 0.1.1.1. 知識點1 0.1.1.2. 代碼1 0.1.1.3. 知識點2 0.1.2. 知識點3 0.1.2.1. 代碼3 0.2. STL 0.2.1. STL 學習, ...
# CPP 學習筆記
可以直接下載pdf CPP 學習筆記
- 0.1. 多線程
- 0.2. STL
- 0.3. 設計模式
- 數據結構與演算法
- Boost 學習筆記
-
QT 學習
- 0.1.1. 坐標系統
- 0.1.2. layouts
- 0.1.3. 控制項
- 0.1.4. 消息基礎
- 0.1.5. QT 消息中級
- 1.0.6. QPainter 和重寫自定義控制項
- 1.0.7. 信號和槽
- 1.0.8. 高級Painter
- 1.0.9. QDialog
- 1.0.10. MainWindow
- 1.0.11. QFile-QBuffer-QXXXXStream-Mapping
- 1.0.12. Socket-TCP-UDP-BOARDCAST-MULI-CAST
- 1.0.13. 關於在new 生成控制項的時候this 的解釋 和 deleteLater
- 1.0.14. QT動態庫
- 1.0.15. QT靜態庫
- 1.0.16. QT JSON
- 1.0.17. QT 加密
- 1.0.18. QSQLDatabase 的使用
- 1.0.19. QSQLDatabase 的使用
- 1.0.20. Qprocess 的使用
0.1. 多線程
0.1.1. 文件操作已經學完,今天看下多線程
0.1.1.1. 知識點1
Linux 下編譯 帶<thread> 的CPP需要加上 -pthread 編譯選項。例如: ``` g++ -std=c++11 -pthread a.cpp<li>QT Creator 編譯帶<thread>的CPP有BUG,暫時不知道怎麼去除! <a id="markdown-0112-代碼1" name="0112-代碼1"></a> #### 0.1.1.2. 代碼1 ```#include <iostream> #include <stdlib.h>v #include <thread> using namespace std; void run(char* p) { int i=0; i=system(p); } int main() { char p[5][20]={ "ls", "echo nihao", "gnome-terminal", "terminator", "ps -aux" }; while("nimei") { static int i(0); if(i<5){ thread *pt=new thread(run,p[i]); i+=1; cout<<"I now is :\t"<<i<<endl; } else{ break; } cout<<"Breaking...."<<endl; } cin.get(); return 0; }
0.1.1.3. 知識點2
關於thread類的內部成關鍵字 | 詳細解釋 |
---|---|
id | Thread的id |
native_handle_type | native_handle_type |
operator= | Move massive Thread |
get_id | get Thread ID |
joinable | get if joinable |
join | join thread |
detach | detach thread |
swap | swap thread |
native_handle | get native handle |
hardware_concurrency[static] | Detect hardware concurrency (public static function) |
0.1.2. 知識點3
線程中變數的競爭控制是通過 mutex automic 來實現的 mutex : 互斥量。需要包含頭文件 <mutex> 來使用 -->速度慢 atomic 原子變數。需要包含頭文件<atomic>來實現 -->速度快,線程安全。0.1.2.1. 代碼3
#include <iostream> #include <stdlib.h> #include <thread> #include <atomic> using namespace std; int count(0); void run() { for(int i(0);i<1000000;i++) { count++; cout<<"\t"<<i<<"\t"<<count<<"\t"; } } int main() { auto n=thread::hardware_concurrency(); thread* pt[n]; for(int z=0;z<n;z++) { pt[z]=new thread(run); pt[z]->detach(); } cout<<"Finally count is \t"<<count<<endl; cout<<"Used "<<n <<"threads"<<endl; cin.get(); return 0; }
運行結果不是1000000×2.
#include <stdlib.h> #include <thread> #include <atomic> using namespace std; int count(0); void run() { for(int i(0);i<1000000;i++) { count++; cout<<"\t"<<i<<"\t"<<count<<"\t"; } } int main() { auto n=thread::hardware_concurrency(); thread* pt[n]; for(int z=0;z<n;z++) { pt[z]=new thread(run); pt[z]->detach(); } cout<<"Finally count is \t"<<count<<endl; cout<<"Used "<<n <<"threads"<<endl; cin.get(); return 0; }
運行結果是1000000×2.正確
atomic 聲明方式為 atomic<int> a(100); 等號初始化會報錯 vim 按CTRL+S 後假死按 CTRL+q 退出0.2. STL
0.2.1. STL 學習,沒有帶筆記本回來。。。我日 2019.11.11 23:21
0.2.1.1. STL的概念
Iterator (迭代器) Container (容器) array Alogrithm (演算法) Adapters (配接器) 用來實現容器之間的轉接面向過程--》面向對象-》基於對象-》泛型
0.2.1.2. 代碼
#include <iostream> #include <vector> //容器 #include <algorithm> //演算法 using namespace std; //專麽實現一個類模板,實現列印 //類模板實現了方法 template <class T> class vector_s { public: void operator()(const T &t1) //重載了小括弧 實現訪問小括弧就直接列印 { cout << t1 << endl; } }; int main(void) { vector<int> myv; myv.push_back(13); myv.push_back(23); myv.push_back(33); myv.push_back(113); myv.push_back(1995); myv.push_back(1996); vector_s<int> print; // 對列印實現實例化 //myv.begin(), myv.end() 是迭代器 本質是指針 // for_each 本質是一個演算法 for_each(myv.begin(), myv.end(), print); cin.get(); return 0; }
註意:演算法需要包含頭文件 <algorithm>
這個遍歷的函數為 for_each 不是foreach
演算法可以適用於任何容器
0.2.1.3. STL抽象的是什麼
-有些演算法並不依賴於數據結構的特定實現,而只依賴於該結構的幾個基本語義屬性
-STL 抽象出的這些基本屬性(concept)成功的將演算法和數據結構相分離,在沒有效率損失的前提下,獲得了極大的彈性!
0.2.2. 六大組件
-容器 (container)
-演算法Algorithm
-迭代器 (iterator)
-仿函數 (Function Object)
-適配器 (Adaptor)
-空間制配器 (allocator)
獲取遠程代碼修改後,想要push到遠端與原來不同的新分支,可以使用下麵的命令實現: git push origin 本地分支:遠端希望創建的分支
例如git下來的分支為master
git branch master git push origin master:my_remote_new_branch #遠端即可創建新的分支my_remote_new_branch,提交本地修改
std::for_each(arr.begin(), arr.end(), func);
比較有用的for_each 用法
for (auto n:Original)
C++ 11 新的for
typename
- 成員函數也可以是模板-
- typename 作為類型前的標識符號-
class MyClass typename T::SubType * ptr; //typename 直接指示 T::SubType * 為一個類型 沒有typename 會被解析為 // T域中的 SubType 靜態成員 乘於(*) ptr. ... };
-typename 的第二個作用:在模板聲明中替換class -
template <typename T > class Myclass;
static_cast 只有當類型轉換有所定義,轉換才會成功。(明確轉換類型)
dynamic_cast 將多態類型向下轉換<downcast> 被轉換的類必須有虛函數。否則失敗
const_cast 用於轉換為const 值
reinterpret_cast 多用於指針個的轉換
C語言的小括弧()可以替換除dymanic_cast 外的所有靜態轉換函數,無法明確顯示使用他們的切確理由
容器的概念
-用於管理一組元素
容器的分類
-序列式容器(Sequence containers)
-每個元素都有固定位置--去結餘插入時機和地點,和元素值無關 -vector list deque
關聯式容器 (Associated containers)
-元素取決於特定的排序準則,和插入順序無關 -set multiset map multimap
array
array <int ,5>={1,2,3,4,5};
-靜態數組,棧上
0.2.2.1. vector 動態數組 堆上
mv.push_back()
-不需要變長,容量較小,array 需要變長,容量較大,用vector
0.2.2.2. tuple 可以存儲不同的數據類型
0.2.2.3. list 適合經常插入,經常刪除的情況
0.2.2.4. list 容器
-list容器是無序容器
-list 容器只能通過迭代器訪問。通過++ -- 遍歷
-list容器可以使用remove()方法刪除元素,
-可以同時正向和反向查找
-可以使用sort()函數排序
-可以使用merge 合併,但是合併之前必須排序
-可以使用unique()函數刪除重覆項,刪除前必須排序。
--merge (使)合併,結合,併入;相融;融入;漸漸消失在某物中
0.2.2.5. set 容器 (紅黑樹容器)
-set容器不能有重覆項,重覆的會被捨棄 -set容器會自動排序 -set 用insert插入元素 -set可以用find()函數查找位置
迴圈加棧
0.2.3. algorithm 演算法
find()函數可以查找數組、容器中的元素。
for_each(); 遍歷每一個元素。
multiset和set差不多,但是允許重覆元素。
迭代器本質是智能指針。
0.2.4. Iterator
0.2.4.1. 仿函數
auto ifind=find_if(mylist.bengin(),mylisy.end(),bindlst(greater<int>(),3));
bindlst 需要頭文件 funtional #include <functional>
bindlst(greater<int>(),3);
綁定一個函數。 greater<int>()
是一個仿函數(functional) 是一個重載了()的類/結構 體 ,可以用來實現一定的演算法策略。
仿函數例子:
#include <list> #include <functional> #include <array> #include <algorithm> using namespace std; class shuchu { public: void operator()(int x) { std::cout<<x<<endl; } }; int main(int argc, char const *argv[]) { /* code */ // array<int,5>array1({1,2,3,4,5}); list <int>ls1; ls1.push_back(1); ls1.push_back(3); ls1.push_back(5); ls1.push_back(7); ls1.push_back(9); auto ib=ls1.begin(); auto ie=ls1.end(); for_each(ib,ie,shuchu()); cin.get(); return 0; }
0.2.5. wmv STL Bug 迭代器
2019.11.15
-智能指針有一個_Ptr屬性,可以列印裡面的指針。
-STL 有bug 先訪問迭代器的_Ptr屬性,再訪問迭代器指針正常,但是反過來會出錯。
-分行列印就沒有問題。
0.2.6. wmv 棧隊列雙端隊列優先隊列
2019.11.15
0.2.6.1. stack 關鍵字可以構建棧
-用法
stack <mystack>; //聲明一個棧
mystack.push(num); //壓棧
mystack.pop(); //出棧
mystack.top(); //獲取第一個元素
stack成員函數示例 -size( ) :返回棧中元素個數 -top( ) :返回棧頂的元素 -pop( ) :從棧中取出並刪除元素 -push(e) :向棧中添加元素e -empty( ) :棧為空時返回true
0.2.6.2. queue 隊列
-queue 英 [kjuː] 美 [kjuː]
n.(人、汽車等的)隊,行列;(儲存的數據)隊列 v.(人、車等)排隊等候;(使)排隊;列隊等待
-queue 需要頭文件 <queue>
-從網上拔來的Queue
queue 操作
queue 和 stack 有一些成員函數相似,但在一些情況下,工作方式有些不同:- front():返回 queue 中第一個元素的引用。如果 queue 是常量,就返回一個常引用;如果 queue 為空,返回值是未定義的。
- back():返回 queue 中最後一個元素的引用。如果 queue 是常量,就返回一個常引用;如果 queue 為空,返回值是未定義的。
- push(const T& obj):在 queue 的尾部添加一個元素的副本。這是通過調用底層容器的成員函數 push_back() 來完成的。
- push(T&& obj):以移動的方式在 queue 的尾部添加元素。這是通過調用底層容器的具有右值引用參數的成員函數 push_back() 來完成的。
- pop():刪除 queue 中的第一個元素。
- size():返回 queue 中元素的個數。
- empty():如果 queue 中沒有元素的話,返回 true。
- emplace():用傳給 emplace() 的參數調用 T 的構造函數,在 queue 的尾部生成對象。
- swap(queue<T> &other_q):將當前 queue 中的元素和參數 queue 中的元素交換。它們需要包含相同類型的元素。也可以調用全局函數模板 swap() 來完成同樣的操作。
queue<T> 模板定義了拷貝和移動版的 operator=(),對於所保存元素類型相同的 queue 對象,它們有一整套的比較運算符,這些運算符的工作方式和 stack 容器相同。
0.2.6.3. deque 雙端隊列
- deque 可以從頭部push_front()和尾部push_back()插入
- deque 可以使用迭代器 可以使用 迭代器+n 訪問刪除
- deque 可以pop_front() pop_back() 從頭部和尾部 刪除元素。
(1) 構造函數
deque():創建一個空deque
deque(int nSize):創建一個deque,元素個數為nSize
deque(int nSize,const T& t):創建一個deque,元素個數為nSize,且值均為t
deque(const deque &):複製構造函數
(2) 增加函數
void push_front(const T& x):雙端隊列頭部增加一個元素X
void push_back(const T& x):雙端隊列尾部增加一個元素x
iterator insert(iterator it,const T& x):雙端隊列中某一元素前增加一個元素x
void insert(iterator it,int n,const T& x):雙端隊列中某一元素前增加n個相同的元素x
void insert(iterator it,const_iterator first,const_iteratorlast):雙端隊列中某一元素前插入另一個相同類型向量的[forst,last)間的數據
(3) 刪除函數
Iterator erase(iterator it):刪除雙端隊列中的某一個元素
Iterator erase(iterator first,iterator last):刪除雙端隊列中[first,last)中的元素
void pop_front():刪除雙端隊列中最前一個元素
void pop_back():刪除雙端隊列中最後一個元素
void clear():清空雙端隊列中最後一個元素
(4) 遍歷函數
reference at(int pos):返回pos位置元素的引用
reference front():返回手元素的引用
reference back():返回尾元素的引用
iterator begin():返迴向量頭指針,指向第一個元素
iterator end():返回指向向量中最後一個元素下一個元素的指針(不包含在向量中)
reverse_iterator rbegin():反向迭代器,指向最後一個元素
reverse_iterator rend():反向迭代器,指向第一個元素的前一個元素
(5) 判斷函數
bool empty() const:向量是否為空,若true,則向量中無元素
(6) 大小函數
Int size() const:返迴向量中元素的個數
int max_size() const:返回最大可允許的雙端對了元素數量值
(7) 其他函數
void swap(deque&):交換兩個同類型向量的數據
void assign(int n,const T& x):向量中第n個元素的值設置為x deque網上扒來的
0.2.6.4. priority_que 優先順序隊列 (不太理解)
- 優先隊列是按照堆來實現的
0.2.7. 紅黑樹容器
0.2.7.1. set 是一個紅黑樹
0.2.8. set map multi-map 紅黑樹
0.2.8.1. set的高級用法
- 紅黑樹,處理純字元串比較少,處理字元串及對象比較多。
- pair 複合集合
- 二叉樹查找依賴於有序。 字元串可以實現有序。
- pair 也是個類模板!起到獲取插入返回值(boolean)的作用。兩個參數,第一個類型,第二個是比大小的方法
- set的每一個節點就是一個節點
- 二叉樹的實現語法一直在在在變 。VS2013 能過的 VS2017 就不能過了!~!!mingw 32又能過,代碼如下:
- set 不能包含同樣的值
- 0-35:40
#include <set> #include <string> #include <stdio.h> #include <string.h> using namespace std; class strless { public: bool operator () (const char* p,const char* p1) { return strcmp(p, p1) < 0; } private: }; int main(void) { const char* cmd[] = { "nihao","spectrc","calc","good" }; set<const char *, strless>myset(cmd,cmd+4,strless()); auto ib = myset.begin(); auto ie = myset.end(); for (auto i : myset) { cout << i << endl; } return 0; }
0.2.8.2. multiset
- 可以插入相同的值
- multiset 的每一個節點是一個鏈表
- 練習代碼如下(mingw 32編譯):
#include <set> #include <string.h> using namespace std; class stu{ public: int id; char p[100]; }; class stuless { public: bool operator ()(const stu &st1,const stu &st2) { return st1.id<st2.id; } }; int main() { stu student[3]={ {99,"zhuang"}, {15,"li"}, {3,"ooooo"} }; stu newstu; newstu.id=100782; strcpy(newstu.p,"nimeide"); multiset<stu,stuless> stu1 (student,student+3,stuless()); stu1.insert(newstu); strcpy(newstu.p,"SBSBSBSB"); stu1.insert(newstu); strcpy(newstu.p,"luo liuo"); stu1.insert(newstu); for(auto i:stu1) { cout<< "\t"<<i.id<<"\t"<<i.p<<endl; } return 0; }
-
輸出
0.2.8.3. map 映射 multimap 多層映射 9.wmv 53:41
- map 也是 紅黑樹,但是能同時映射多個數據
- map 需要頭文件 <map>
- 映射都是左邊映射到右邊。訪問時用右邊訪問左邊。可以通過對等的映射查找
- 示例代碼如下:
#include <string> #include <map> #include <stdlib.h> using namespace std; class worker{ public: int id; string name; string work; }; class winfo{ public: int randid; worker w1; }; int main() { system("chcp 65001"); winfo warr[]={ {1,{10,"李四","mugong"}}, {2,{9,"張三","mugong"}}, {8,{5,"wangermazi","mugong"}}, {20,{3,"gg","mugong"}}, {30,{1,"ww張三","mugong"}} }; map <int,worker> m; for(auto i : warr) { static int n=0; m[warr[n].randid]=warr[n].w1; n++; } auto ib=m.begin(); auto ie=m.end(); for(;ib!=ie;ib++) { cout<<"\t winfo.randid is \t"<<(*ib).first<<" worker info is \t"<<(*ib).second.id<<"\t"<<(*ib).second.name <<"\t"<<(*ib).second.work<<"\t"<<endl; } return 0; }
-
輸出
0.2.8.4. pair 關鍵字 9.wmv 01:23:15
- 用於插入 複雜映射類型
- multimap set map 每一個節點就是一個 pair
- 用法:
m.insert(pair<const char*,int> ("第一個"),1); m.insert(pair<const char*,int> ("第二個"),2); m.insert(pair<const char*,int> ("第三個"),5); m.insert(pair<const char*,int> ("第四個"),8);
0.2.8.5. hash_set 和hash_map 9.wmv 01:33:10
- 作用:把比較大的數據抽象得比較小
- hash_set 不會自動排序 查找時一次就足夠了。而set需要 log2n 次
- 適用於精確查找,一次就能找到。比二分查找要快
- hash_set 的經典用法 判斷數據是否相等
- hash_set、hash_map 不會自動排序
- hash演算法依賴於hash_table
0.2.8.6. equal_range()
- 找到紅黑樹的鏈表節點,遍歷所有節點
- first為鏈表的首節點,second 為最後一個空節點
0.2.9. string 本質是一個容器
- C語言中 下列代碼是錯誤的:
char str[54]; str="123456";
-
erase() 函數可刪除字元串。 str1.erase(3,4); erase(str1.begin(),str.begin()+2);
-
replace() 替換函數 str1.replace(3,3,"China");str1.replace(3,"China"); str1.replace(3,"China"); replace (位置,長度,字元串);
-
str.find() 查找字元串,找到第一個匹配的字元的位置,找不到返回-1;
-
rfind() 反向查找,返回找的的第一個的匹配的字元串的位置。找不到返回-1;
-
find_first_of () 找到第一個並返回所在位置。
-
find_first_not_of () 找到第一個不匹配的並返回所在位置。
-
find_last_of () 找到最後一個匹配的並返回所在位置。
-
find_last_not_of () 找到最後一個不匹配的並返回所在位置。
0.2.9.0.1. 網上扒來的 string 介紹
0.2.10. GPU編程
0.2.10.1. Lamda 表達式 C++ AMP 編程
- 函數包裝器(LAMDA 表達式,類似JS裡面的匿名函數) : 需要頭文件
- GPU 強項在於並行計算,CPU強項在於單點計算
auto func=[](int a ,int b){ return a+b;}; for_each(myvector.begin(),myvector.end(),[](int a){return a*=2;cout<<a<<endl;});
- C++ AMP 計算演示 (VS 2017中編譯失敗)
- VS2017 中錯誤信息:
嚴重性 代碼 說明 項目 文件 行 禁止顯示狀態 錯誤 C3861 “_Access”: 找不到標識符 GPU_hello c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.15.26726\include\amp.h 2616
嚴重性 代碼 說明 項目 文件 行 禁止顯示狀態 錯誤 C3588 在 amp 限制代碼中不支持從“unknown-type”轉換為“void *” GPU_hello c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.15.26726\include\amp.h 2616
#include <amp.h> #include <iostream> using namespace std; using namespace concurrency; int main(void) { int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; array_view<int> av(10, a); //GPU 計算結構 AV 存儲到GPU的顯存 /* *[=](index<1>idx) restrict (amp) {av[idx] *= 2; } * [=] 標識直接操作這個數據 * restrict (amp) 標識定位到 GPU進行運算 *這個表達式為Lambda表達式 */ parallel_for_each(av.extent, [=](index<1> idx) restrict (amp) {av[idx] *= 2; }); for (int i = 0; i < 10; i++) { cout << "\t" << av[i] << endl; } cin.get(); }
0.3. 設計模式
0.3.1. 備忘錄模式
-
在一個類內部記錄另一個類的快照狀態的模式。可以再合適的時候跳回覆用
-
設計備忘錄的三大步驟:
- 設計記錄的節點,存儲記錄 2.設計記錄的存儲: vector list map set 可以使 鏈表 圖 數組 樹 3.操作記錄的類,記錄節點狀態,設置節點狀態,顯示節點狀態
0.3.2. 策略模式
-
策略模式針對一組演算法,將每一個演算法封裝到具有共同介面的獨立類中。
-
從而使得他們可以相互轉換,策略模式可以在不影響客戶端的情況下使演算法發生改變。策略模式把行為和環境分離開來,環境類負責維持和查詢行為類。
-
策略模式依賴多態,策略模式的抽象類,介面,抽象類的指針可以訪問所有子類對象(純虛函數)
-
各種策略的實現類。都必須集成抽象類。
0.3.3. 設計模式 抽象工廠模式
- 工廠模式: 客戶類和工廠類分開。
- 消費者需要任何產品,只需要和工廠請求就可以了。
- 消費者無需修改就可以接納新產品,缺點是當產品修改時,工廠類也要做相應的修改
=======
0.3.4. 簡單工廠模式
- 基類存放數據 派生類存放操作
- 再實現一個調用各個操作的靜態類,調用時返回派生類指針
代碼: simple_factory
0.3.5. 方法工廠模式
- 把操作和實例化工廠的類分別抽象出來
- 通過繼承抽象類實現不同的操作
- 方法工廠模式就是簡單工廠模式把工廠進行抽象並且進行封裝後得到的
代碼: factory_method
不能在linux 下編譯!!! 報錯 only nonstatic member functions may be virtual