一、C++基礎(chǔ)語法學(xué)習(xí)
1.常量指針 : const int *? b :? 指針的地址可以修改,但是內(nèi)容不可以修改
2.指針常量 :? int * const? b :? 指針的內(nèi)容可以修改,但是地址不可以修改
3.引用 : int a = 20 ;? int &b = a;
? ? ? ?a. 引用必須初始化?
?? ? ? b. 引用一旦初始化就不能發(fā)生改變
?? ? ? c. 引用本質(zhì)是 : 指針常量,地址不可以改變,數(shù)據(jù)可以改變
?4.std::uint64_t? :? unsigned long long
?? ? ? std::uint32_t? ? :? ? unsigned int
?? ? ? std::uint16_t? ? :? ? unsigned short?
?? ? ? std::uint8_t.? ? :? ? ? unsigned char
?5. 將字符串轉(zhuǎn)為long、int 、float類型
????????String —> 無符號long? ? :? std::stoull
????????Strng —-> 無符號int? ? ? :? std::stoui
? ? ? ? Strng —-> 無符號float? :? std::stouf
? 6. 轉(zhuǎn)意符
? ? ? std::string str1 = "45";
? ? ? int myint1 = std::stoi(str1);
? ? ? std::cout << "std::stoi(\"" << str1 << "\") is " << myint1 << '\n';
? ? ? 輸出結(jié)果 : std::stoi("45") is 45
? 7. C++ 數(shù)據(jù)類型轉(zhuǎn)換
? ? ? static_cast : 靜態(tài)類型轉(zhuǎn)換,明確把隱式轉(zhuǎn)換變?yōu)轱@示轉(zhuǎn)換,便與可讀性
? ? ? reinterpreter_cast : 重新解釋類型,強制類型轉(zhuǎn)換
? ? ? dynamic_cast : 用于虛函數(shù)基類與派生類之間引用和對象的轉(zhuǎn)換
? ? ? const_cast : 去const屬性
8. C++函數(shù)模版的機制
? ? ? 編譯器會對函數(shù)模版進行兩次編譯,第一次是對函數(shù)模版本身編譯,第二次是在運行時候參數(shù)替換后編譯
9.智能指針學(xué)習(xí)
? ? auto_ptr :?
? ? ????缺點:在編譯時無法檢測出來,再運行時才報錯。創(chuàng)建形式是通過拷貝構(gòu)造函數(shù)和復(fù)值,函數(shù)運行時會出現(xiàn)空指針
? ? unique_ptr :?
? ? ????優(yōu)點:拷貝構(gòu)造函數(shù)和復(fù)值函數(shù)都被delete,禁止使用拷貝構(gòu)造函數(shù)和復(fù)值函數(shù)創(chuàng)建對象
? ? shared_ptr : 強指針
? ? ? ? 優(yōu)點:可以使用構(gòu)造函數(shù)和復(fù)值函數(shù)創(chuàng)建對象
? ? weak_ptr : 弱指針
? ? 拓展知識:
? ? shared_from_this : 可以返回一個shard_ptr指針,里面是有weak_ptr實現(xiàn)的
? ??weak_ptr.lock() 可以拿到一個shared_ptr指針
? ? shared_ptr線程安全性 : 多個線程同時讀同一個shared_ptr對象是線程安全的,但是如果是多個線程對同一個shared_ptr對象進行讀和寫,則需要加鎖
?10. move變量 :?將左值轉(zhuǎn)換為右值,將A對象的所有權(quán)轉(zhuǎn)移到B對象,只是轉(zhuǎn)移,沒有內(nèi)存拷貝,A然后被釋放,B獲得A所有的能力
二、C++多線程學(xué)習(xí)
? ? C++11多線程支持thread、atomic、mutex、condition_variable、future5個關(guān)鍵庫
thread : 線程類
atomic :??原子操作
? ? atomic :
? ? atomic_flag :?
mutex : 互斥量
? ? mutex : 基本Mutex類
? ? ? ? lock()、unlock()、try_lock()
? ? recursive_mutex : 遞歸Mutex類,遞歸上鎖
? ? timed_mutex : 定時Mutex類
? ??????? try_lock_for : 等一段時間是否可以獲得鎖,獲得返回為true,沒有獲得返回為flase
? ? ? ? ?try_lock_until : 等到某個時間是否可以獲得鎖,獲得返回為true,沒有獲得返回為flase ? ? ? ? ??
????recursive_timed_mutex? :?定時遞歸Mutex類
? ? lock_guard :??當多個線程搶占資源時候,其中一個鎖在異常情況下無法釋放,通過這種方式,可以釋放鎖,防止死鎖現(xiàn)象的放生
? ???????使用方法:
? ? ? ??mutex mMutex;
? ??????lock_guard sk1(mMutex);
? ? unique_lock :?它具有l(wèi)ock_guard一切能力,也可以控制解鎖和非解鎖更加靈活的控制使用范圍
????? ? 使用方法:
????????mutex mMutex;
????????unique_lock sk2(mMutex);? ? ? ? ? ?
????????sk2.lock();
????????sk2.unlock();
condition_variable :??條件變量,可以做到不同線程通信
? ? condition_variable :? 需要搭配unique_lock使用
? ? condition_variable_any :? 可以搭配任何mutex使用,但效率比condition_variable低
? ? 常用方法:??
? ? ? ? wait : 阻塞自己,等待喚醒
? ? ? ? wait_for : 等某一段時間,一直阻塞自己,等待喚醒
? ? ? ? wait_until :? 等到某個時間,一直阻塞自己,等待喚醒
? ? ? ? notify_one : 喚醒某一個?阻塞線程
? ? ? ? notify_all :? ?喚醒所有阻塞線程? ?
future :?? 異步操作,可以拿到不同線程的結(jié)果? ? ??
Futures類的使用:
int sum(int a, int b) {
sleep_for(chrono::seconds(5));
? ? return a + b;
}
future result = async(sum, 123, 456);? ??
result.wait();? ? ? ? ? ?//等待結(jié)果算出
int sum = result.get();? ? ? ?//得到結(jié)果
Promise類:
使用方法:
void work(promise<int> &prom) {
sleep_for(chrono::seconds(5));
? ? //設(shè)置結(jié)果值
? ? prom.set_value(6666);
}
promise<int>?pro;
future result = pro.get_future();
thread t1(work, ref(pro));
t1.detach();
int sum = result.get();
cout<< "輸出結(jié)果:" << sum<< endl;
三、數(shù)據(jù)結(jié)構(gòu)
? ? 1. vector : 一塊連續(xù)、單向開口、動態(tài)數(shù)組(myFirst、myLast、myEnd三個指針)
? ? 2. deque :?一塊連續(xù)、雙向開口、動態(tài)數(shù)組(核心:中控器)
? ? 3. list :? 一塊非連續(xù)、非順序的雙向鏈表
? ? 4.set和multiset : 底層都是紅黑樹作為實現(xiàn)
? ? 4. map和multimap :??底層都是紅黑樹作為實現(xiàn)
四、C++面試總結(jié)
1.vector :?因為vector使用數(shù)組實現(xiàn)的,因此元素是保存在連續(xù)的內(nèi)存中的,所以通過索引取值的速度非常快
? ?size的大小:結(jié)束的數(shù)據(jù)-開始的數(shù)據(jù)
? ?capacity的大小:申請一塊連續(xù)的內(nèi)存大小
2.resize()、reserve()兩個函數(shù)對比
? resize : 影響的存儲的數(shù)據(jù)的大小,也有可能影響capacity這個大小,因為size長度比capacity的長度大,這個時候就需要擴容
? reserve:它只影響capacity的大小,不會影響size的大小
? 擴容時候會把之前舊數(shù)據(jù)拷貝到新的數(shù)據(jù)里面,然后再把老的數(shù)據(jù)清除掉
3. list :?在底層使用一個雙向的環(huán)形鏈表實現(xiàn)的,所以在任意位置進行增加或者刪除速度都比較快,都是指針交換
4.Map、Multimap、Unordered_map、Unordered_multimap
? ?Map和Multimap:底層基于紅黑樹,元素自動有序,且插入、刪除效率高,時間復(fù)雜度是O(logN)
? ?Unordered_map和Unordered_multimap :?底層基于哈希表,故元素?zé)o序,查找效率高,時間復(fù)雜度是O(1)
5.迭代器和指針的區(qū)別
? ?迭代器(iterator)概念 : 對容器里面的數(shù)據(jù)進行遍歷
迭代器:對指針里面的功能進行一系列封裝的指針,它是一個類模版。
? ? 指針:它是一個存放對象的地址的指針變量。
? ? 常用設(shè)計模式:單例模式、外觀模式、適配器模式、責(zé)任鏈模式、裝飾者模式、模版模式、工廠模式、組合模式、代理模式、觀察者模式、策略模式、建造者模式
6.模版 :template作為關(guān)鍵字
? ? 類模類和函數(shù)模版的區(qū)別
? ?類模類:調(diào)用時候類時候參數(shù)類型必須是顯性,指定好類型
? ?函數(shù)模版:調(diào)用時候函數(shù)時候參數(shù)可以顯性或隱性,指定好類型或者不指定類型
7.友元函數(shù),需要用friend來作為定義
????類的友元函數(shù)是定義在類外部,但有權(quán)訪問類的所有私有(private)成員和保護(protected)成員。盡管友元函數(shù)的原型有在類的定義中出現(xiàn)過,但是友元函數(shù)并不是成員函數(shù)。
8.指針和引用的區(qū)別
? ?引用創(chuàng)建時候同時被初始化,引用不能為null,指針可以在任何場景下初始化,指針可以是null
? ? 引用一旦初始化就不能修改,指針隨時可以改變
? ? 引用的sizeof取決于變量的大小,指針的sizeof的大小是4個字節(jié)
????引用有編譯檢查,指針無編譯檢查
? ??如果返回動態(tài)內(nèi)存分配的對象或者內(nèi)存,必須使用指針, 不使用引用(可能引起內(nèi)存泄露)
9.虛函數(shù)用sizeof來看大小
????虛函數(shù)用sizeof大小是4,(32位計算器)虛函數(shù)指針的大小是4,指針用sizeof去計算大小都是4
10.虛函數(shù)和純虛函的區(qū)別
????虛函數(shù):它是一個繼承,子類不一定需要實現(xiàn),繼承只能實現(xiàn)一個,構(gòu)造函數(shù)不能使用虛函數(shù)
????純虛函數(shù):它是一個接口,子類必須實現(xiàn),它是在方法后面加個=0,接口可以實現(xiàn)多實現(xiàn)
????什么情況下需要將析構(gòu)函數(shù)定義為虛函數(shù)?
????當一個類里面有虛函數(shù)時候,繼承之后就會調(diào)用該方法,這樣會導(dǎo)致內(nèi)存泄漏,才必須再析構(gòu)函數(shù)加virtual這個關(guān)鍵字
11.struct和class的區(qū)別? ??
? ? class默認訪問是private,而struct默認訪問是public
? ? 實例化的class存在堆內(nèi)存中,而實例化的struct存在棧中,它不用執(zhí)行析構(gòu)函數(shù),執(zhí)行效率更高
? ? class可以繼承,而struct不能繼承
12.什么是左值、什么是右值
? ? ? 左值 : 變量是左值,可以放在左邊和右邊,地址是可以修改的
? ? ? 右值 :? 常量是右值,只能放在右邊,地址不可以修改的
13. include的""和<>區(qū)別
? ??#include“”優(yōu)先從自己定義的源文件中查找,找不到之后才去標準庫文件中查找。
????#include<>優(yōu)先從引入的標準庫文件中查找。<>里面一般都放標準庫.h。
14.inline內(nèi)聯(lián)函數(shù)的作用以及缺點
? ? ? ?作用:代碼過短但被經(jīng)常調(diào)用,需要使用內(nèi)聯(lián)函數(shù),這樣可以大大提高運行效率
? ? ? ?缺點:方法不能過長,也不能有循環(huán)語句在里面
? ? ? ? 不使用inline內(nèi)聯(lián)函數(shù):
? ??????int add(int a, int b) {
????????????return a + b;? ? ?------------>? (內(nèi)聯(lián)函數(shù))
????????}
? ? ? ? 使用inline函數(shù): inline void add(int a , int b)
15. 智能指針
? ? 智能指針有:auto_ptr(自動)、shared_ptr(共享)、weak_ptr、unique_ptr(獨占)
? ? auto_ptr(C98) : 當執(zhí)行拷貝構(gòu)造和賦值構(gòu)造函數(shù)會有控制權(quán)轉(zhuǎn)移,會出現(xiàn)空指針。
????shared_ptr : 共享指針(強指針)
????weak_ptr :? ?弱指針
????unique_ptr : 獨占指針
? ? ?作用:申請的空間在函數(shù)結(jié)束時忘記釋放,類會自動調(diào)用析構(gòu)函數(shù),防止造成內(nèi)存泄漏
shared_ptr的原理:
初始化以及增加情況
?????1.第一次創(chuàng)建shared_ptr時候,對象計數(shù)和引用計數(shù)設(shè)置為1
?????2.當shared_ptr賦值給新的shared_ptr的時候,對象計數(shù)+1,引用計數(shù)不變
?????3.當shared_ptr賦值給新的weak_ptr的時候,對象計數(shù)不變,引用計數(shù)+1
?????4.當weak_ptr獲取shared_ptr的時候,對象計數(shù)不變,引用計數(shù)+1
減少以及銷毀情況
?????1.當shared_ptr對象析構(gòu)時候,對象計數(shù)-1,引用計數(shù)不變,當對象計數(shù)為0時候,SharedPtr釋放內(nèi)存,引用計數(shù)-1。
????2.當weak_ptr對象析構(gòu)時候,對象計數(shù)不變,引用計數(shù)-1,當引用計數(shù)為0時候,*refCount釋放內(nèi)存
16.const的關(guān)鍵字的作用?
? ? ? 作用:使內(nèi)容和變量只有讀的功能
? ? ? 作用范圍:
? ? ? ?變量、指針:該函數(shù)只具有讀的功能,const修飾的變量一定要在構(gòu)造函數(shù)內(nèi)部初始化
? ? ? ?函數(shù):表明是一個常函數(shù),里面的函數(shù)的變量不能修改
17.深拷貝和淺拷貝的區(qū)別
? ? ? ? 淺拷貝:只是對指針進行拷貝,最終兩個指針指向還是同一塊地址
? ? ? ? 深拷貝:不只是對指針進行拷貝,里面內(nèi)容也會一起拷貝,最終兩塊指針只向不同的地址
18.static的作用
? ? 作用:數(shù)據(jù)共享,減小內(nèi)存,數(shù)據(jù)存放在靜態(tài)區(qū),可以保持封裝特性,避免命名沖突的問題,不能和const連用,因為static里面沒有this這個對象
19.volatile的作用
? ? 數(shù)據(jù)不是寫到寄存器里面,而是直接寫在內(nèi)存中,表現(xiàn)的是可見性,只是限制編譯器優(yōu)化的作用,表現(xiàn)的是禁止指令重排序
20.數(shù)組指針和指針數(shù)組
????數(shù)組指針定義:? int (*a)[5] , 它是一個指針,指向一個包含5個int數(shù)組的首地址
????指針數(shù)組定義:? int * a[5] ,它是一個數(shù)組,里面存著5個指針
????區(qū)別:指針數(shù)組的sizeof是取決于數(shù)組的長度,數(shù)組指針的sizeof是4個字節(jié)
21.面向?qū)ο蟮奶卣?/h4>
? ? ?繼承、封裝、多態(tài)? ? ? ?
22.賦值構(gòu)造函數(shù) : 又稱拷貝構(gòu)造函數(shù)
使用場景:
? ? a、一個對象以值傳遞方式傳入函數(shù)體? ??
? ? b、一個對象以值傳遞的方式從函數(shù)返回
? ? c、一個對象通過另一個對象進行初始化
好處:防止沒有執(zhí)行a、b之后,一個對象通過另一個對象初始化,就會導(dǎo)致一個指針指向已經(jīng)刪除的空間
23.內(nèi)存的分配
? ? 靜態(tài)存儲區(qū)域:負責(zé)存儲靜態(tài)成員
? ? 棧存儲區(qū)域: 負責(zé)存儲臨時變量或者局部變量
? ? 堆存儲區(qū)域:負責(zé)存儲new malloc等創(chuàng)建的動態(tài)生成的對象
24.new delete 和 malloc free的區(qū)別
? ? a、malloc/free 是c語言中的庫函數(shù),需要頭文件支持;而new/delete 是c++中的關(guān)鍵字
? ? b、malloc需要顯式指出所需內(nèi)存的大小,new是通過編譯器內(nèi)部計算
? ? c、malloc內(nèi)存分配成功時,返回的是void*,需要轉(zhuǎn)換成所需要的類型,new內(nèi)存分配成功時,返回的是對象類型的指針
? ? d、free只是負責(zé)釋放內(nèi)存,delete是調(diào)用析構(gòu)函數(shù)再釋放內(nèi)存
25. const和#define的區(qū)別
? ? const有數(shù)據(jù)類型,而#define沒有數(shù)據(jù)類型
? ? const是在編譯過程進行檢查,而#define是預(yù)編譯階段(#代表預(yù)編譯),會比較安全
26. 重載、重寫、隱藏(重定義)的區(qū)別
? ? ? ?重載:在同一個類,方法名一樣,參數(shù)不同或者返回類型不同
? ? ? ? 重寫:在父類、子類中,父類的抽象方法在子類實現(xiàn),子類和父類方法完全一致
? ? ? ? 隱藏:
? ? ? ? a、在父類、子類中,父類的方法在子類實現(xiàn),子類和父類方法完全一致(沒有抽象方法)
? ? ? ? ? ? b、在父類、子類中,父類的抽象方法在子類實現(xiàn),子類重載父類
27.?構(gòu)造函數(shù)為什么不能是虛函數(shù)?
? ? ? ?a. 從空間角度分析:vtable指針是存儲在對象的內(nèi)存空間的,構(gòu)造函數(shù)如果是虛函數(shù),對象還沒有實例化,也就說內(nèi)存空間還沒有,所以不能構(gòu)造函數(shù)不能為虛函數(shù)
? ? ? ? b. 從使用角度分析:虛函數(shù)可以繼承,如果子類繼承父類的構(gòu)造方法,就不能正確識別對象類型從而不能正確調(diào)用析構(gòu)函數(shù)
28.堆內(nèi)存和棧內(nèi)存的區(qū)別
? ? a.棧內(nèi)存由操作系統(tǒng)分配,堆內(nèi)存由程序員自己分配。
? ? b.棧內(nèi)存空間大小是固定的,堆的大小受限于系統(tǒng)中有效地虛擬內(nèi)存。
? ? c.棧的空間由系統(tǒng)決定合適釋放,堆內(nèi)存需要自己決定何時釋放。
? ? d.堆的使用容易產(chǎn)生碎片,但是使用方便。
29. 內(nèi)存對齊
? ??#pragma? pack(n) , 默認為#pragma? pack(4)個字節(jié)對齊?
30. explicit 的關(guān)鍵字
? ? ?用來防止由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換
31.C++中拷貝構(gòu)造函數(shù)的參數(shù)為何一定要用引用類型
????首先可以減少一次內(nèi)存拷貝,其次就是防止創(chuàng)建無限遞歸下去? ??
32.數(shù)組和指針的區(qū)別
? ? a. 數(shù)組的sizeof的大小取決于里面變量多少,指針sizeof大小為4
? ? b. 數(shù)組不能操作++或者--,指針可以執(zhí)行++或者--
? ? c. 數(shù)組不能隨意改地址,指針隨意可以改地址
33.set和map的實現(xiàn)以及區(qū)別
? ?實現(xiàn):
????set和map都是基于紅黑樹實現(xiàn)的
? ? 區(qū)別:
? ? a. map中的元素是key-value形式,set只有key的數(shù)值
? ? b.?map支持下標操做,set不支持下標操做
34.Asan的作用以及原理
????a.作用:? Asan庫以16個字節(jié)作為對齊 (#pragma? pack(16))
? ? ? ? ?使用已釋放內(nèi)存(野指針)
? ? ? ? ?堆內(nèi)存越界
? ? ? ? ?棧內(nèi)存越界
? ? ? ? ?全局變量越界
? ? ? ? ? 內(nèi)存泄漏
? ? b. 原理 :? Asan庫是由編譯器插樁模塊和運行時庫組成,進程的虛擬內(nèi)存空間被ASAN劃分為2個獨立的部分,一個是主內(nèi)存,另一個是影子內(nèi)存區(qū)(Shadow),運行時庫(libasan.so.x)會接管malloc和free()函數(shù)接管,將主內(nèi)存通過"比例+偏移映射算法"與影子內(nèi)存一一對應(yīng),形成映射關(guān)系,再通過插樁形式生成對應(yīng)的匯編存在寄存器中。
35. 虛函數(shù)的原理
編譯器處理虛函數(shù)的方法是:為每個類對象添加一個隱藏成員,隱藏成員中保存了一個指向函數(shù)地址數(shù)組的指針,稱為虛表指針(vptr),這種數(shù)組成為虛函數(shù)表(virtual function table, vtbl)即每個類使用一個虛函數(shù)表,每個類對象用一個虛表指針。
繼承虛函數(shù)情況 :
一般繼承時,子類的虛函數(shù)表中先將父類虛函數(shù)放在前,再放自己的虛函數(shù)指針。
如果子類覆蓋了父類的虛函數(shù),將被放到了虛表中原來父類虛函數(shù)的位置。
在多繼承的情況下,每個父類都有自己的虛表,子類的成員函數(shù)被放到了第一個父類的表中
so存放位置:
naviengine/build/intermediates/cmake/release/
?addr2line存放位置:
/Users/名字/Library/Android/sdk/ndk/16.1.4479499/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line -e (so存放的位置)?000b0eae
玄馬教育:
https://space.bilibili.com/477729104/video?tid=0&page=1&keyword=&order=pubdate?
多線程講解:
https://space.bilibili.com/147020887/channel/seriesdetail?sid=1745830
C++中文學(xué)習(xí)網(wǎng)址:
https://zh.cppreference.com/w/cpp
CMake網(wǎng)址:
https://www.bookstack.cn/read/CMake-Cookbook/README.md
C++顯示匯編的編程網(wǎng)址:
https://godbolt.org/
TutorialsPoint: 高級語言文檔教程:
https://www.tutorialspoint.com/cplusplus/index.htm
Awesome C++ : 常用框架使用
https://link.zhihu.com/?target=https%3A//github.com/fffaraz/awesome-cpp
explicit用來防止由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換