《逆襲進大廠》系列之C++篇No.91-100
本文源自于個人github倉庫:https://github.com/forthespada/InterviewGuide
github倉庫內有PDF版本下載方式,歡迎各位star、fork~
立志收錄計算機校招、社招面試最全面試八股文,無內鬼來點八股文~
91、幾個this指針的易混問題
A. this指針是什么時候創(chuàng)建的?
this在成員函數的開始執(zhí)行前構造,在成員的執(zhí)行結束后清除。
但是如果class或者struct里面沒有方法的話,它們是沒有構造函數的,只能當做C的struct使用。采用TYPE xx的方式定義的話,在棧里分配內存,這時候this指針的值就是這塊內存的地址。采用new的方式創(chuàng)建對象的話,在堆里分配內存,new操作符通過eax(累加寄存器)返回分配的地址,然后設置給指針變量。之后去調用構造函數(如果有構造函數的話),這時將這個內存塊的地址傳給ecx,之后構造函數里面怎么處理請看上面的回答
B. this指針存放在何處?堆、棧、全局變量,還是其他?
this指針會因編譯器不同而有不同的放置位置。可能是棧,也可能是寄存器,甚至全局變量。在匯編級別里面,一個值只會以3種形式出現:立即數、寄存器值和內存變量值。不是存放在寄存器就是存放在內存中,它們并不是和高級語言變量對應的。
C. this指針是如何傳遞類中的函數的?綁定?還是在函數參數的首參數就是this指針?那么,this指針又是如何找到“類實例后函數的”?
大多數編譯器通過ecx(寄數寄存器)寄存器傳遞this指針。事實上,這也是一個潛規(guī)則。一般來說,不同編譯器都會遵從一致的傳參規(guī)則,否則不同編譯器產生的obj就無法匹配了。
在call之前,編譯器會把對應的對象地址放到eax中。this是通過函數參數的首參來傳遞的。this指針在調用之前生成,至于“類實例后函數”,沒有這個說法。類在實例化時,只分配類中的變量空間,并沒有為函數分配空間。自從類的函數定義完成后,它就在那兒,不會跑的
D. this指針是如何訪問類中的變量的?
如果不是類,而是結構體的話,那么,如何通過結構指針來訪問結構中的變量呢?如果你明白這一點的話,就很容易理解這個問題了。
在C++中,類和結構是只有一個區(qū)別的:類的成員默認是private,而結構是public。
this是類的指針,如果換成結構體,那this就是結構的指針了。
E.我們只有獲得一個對象后,才能通過對象使用this指針。如果我們知道一個對象this指針的位置,可以直接使用嗎?
this指針只有在成員函數中才有定義。因此,你獲得一個對象后,也不能通過對象使用this指針。所以,我們無法知道一個對象的this指針的位置(只有在成員函數里才有this指針的位置)。當然,在成員函數里,你是可以知道this指針的位置的(可以通過&this獲得),也可以直接使用它。
F.每個類編譯后,是否創(chuàng)建一個類中函數表保存函數指針,以便用來調用函數?
普通的類函數(不論是成員函數,還是靜態(tài)函數)都不會創(chuàng)建一個函數表來保存函數指針。只有虛函數才會被放到函數表中。但是,即使是虛函數,如果編譯期就能明確知道調用的是哪個函數,編譯器就不會通過函數表中的指針來間接調用,而是會直接調用該函數。正是由于this指針的存在,用來指向不同的對象,從而確保不同對象之間調用相同的函數可以互不干擾
《C++中this指針的用法詳解》http://blog.chinaunix.net/uid-21411227-id-1826942.html
92、構造函數、拷貝構造函數和賦值操作符的區(qū)別
構造函數
對象不存在,沒用別的對象初始化,在創(chuàng)建一個新的對象時調用構造函數
拷貝構造函數
對象不存在,但是使用別的已經存在的對象來進行初始化
賦值運算符
對象存在,用別的對象給它賦值,這屬于重載“=”號運算符的范疇,“=”號兩側的對象都是已存在的
舉個例子:
#include <iostream> using namespace std; class A { public: A() { cout << "我是構造函數" << endl; } A(const A& a) { cout << "我是拷貝構造函數" << endl; } A& operator = (A& a) { cout << "我是賦值操作符" << endl; return *this; } ~A() {}; }; int main() { A a1; //調用構造函數 A a2 = a1; //調用拷貝構造函數 a2 = a1; //調用賦值操作符 return 0; } //輸出結果 //我是構造函數 //我是拷貝構造函數 //我是賦值操作符
93、拷貝構造函數和賦值運算符重載的區(qū)別?
拷貝構造函數是函數,賦值運算符是運算符重載。
拷貝構造函數會生成新的類對象,賦值運算符不能。
拷貝構造函數是直接構造一個新的類對象,所以在初始化對象前不需要檢查源對象和新建對象是否相同;賦值運算符需要上述操作并提供兩套不同的復制策略,另外賦值運算符中如果原來的對象有內存分配則需要先把內存釋放掉。
形參傳遞是調用拷貝構造函數(調用的被賦值對象的拷貝構造函數),但并不是所有出現"="的地方都是使用賦值運算符,如下:
Student s; Student s1 = s; // 調用拷貝構造函數 Student s2; s2 = s; // 賦值運算符操作
注:類中有指針變量時要重寫析構函數、拷貝構造函數和賦值運算符
94、智能指針的作用;
1) C++11中引入了智能指針的概念,方便管理堆內存。使用普通指針,容易造成堆內存泄露(忘記釋放),二次釋放,程序發(fā)生異常時內存泄露等問題等,使用智能指針能更好的管理堆內存。
2) 智能指針在C++11版本之后提供,包含在頭文件<memory>中,shared_ptr、unique_ptr、weak_ptr。shared_ptr多個指針指向相同的對象。shared_ptr使用引用計數,每一個shared_ptr的拷貝都指向相同的內存。每使用他一次,內部的引用計數加1,每析構一次,內部的引用計數減1,減為0時,自動刪除所指向的堆內存。shared_ptr內部的引用計數是線程安全的,但是對象的讀取需要加鎖。</memory>
3) 初始化。智能指針是個模板類,可以指定類型,傳入指針通過構造函數初始化。也可以使用make_shared函數初始化。不能將指針直接賦值給一個智能指針,一個是類,一個是指針。例如std::shared_ptr<int> p4 = new int(1);的寫法是錯誤的</int>
拷貝和賦值??截愂沟脤ο蟮囊糜嫈翟黾?,賦值使得原對象引用計數減1,當計數為0時,自動釋放內存。后來指向的對象引用計數加1,指向后來的對象
4) unique_ptr“唯一”擁有其所指對象,同一時刻只能有一個unique_ptr指向給定對象(通過禁止拷貝語義、只有移動語義來實現)。相比與原始指針unique_ptr用于其RAII的特性,使得在出現異常的情況下,動態(tài)資源能得到釋放。unique_ptr指針本身的生命周期:從unique_ptr指針創(chuàng)建時開始,直到離開作用域。離開作用域時,若其指向對象,則將其所指對象銷毀(默認使用delete操作符,用戶可指定其他操作)。unique_ptr指針與其所指對象的關系:在智能指針生命周期內,可以改變智能指針所指對象,如創(chuàng)建智能指針時通過構造函數指定、通過reset方法重新指定、通過release方法釋放所有權、通過移動語義轉移所有權。
5) 智能指針類將一個計數器與類指向的對象相關聯,引用計數跟蹤該類有多少個對象共享同一指針。每次創(chuàng)建類的新對象時,初始化指針并將引用計數置為1;當對象作為另一對象的副本而創(chuàng)建時,拷貝構造函數拷貝指針并增加與之相應的引用計數;對一個對象進行賦值時,賦值操作符減少左操作數所指對象的引用計數(如果引用計數為減至0,則刪除對象),并增加右操作數所指對象的引用計數;調用析構函數時,構造函數減少引用計數(如果引用計數減至0,則刪除基礎對象)。
6) weak_ptr 是一種不控制對象生命周期的智能指針, 它指向一個 shared_ptr 管理的對象. 進行該對象的內存管理的是那個強引用的 shared_ptr. weak_ptr只是提供了對管理對象的一個訪問手段。weak_ptr 設計的目的是為配合 shared_ptr 而引入的一種智能指針來協助 shared_ptr 工作, 它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構造, 它的構造和析構不會引起引用記數的增加或減少.
95、說說你了解的auto_ptr作用
1) auto_ptr的出現,主要是為了解決“有異常拋出時發(fā)生內存泄漏”的問題;拋出異常,將導致指針p所指向的空間得不到釋放而導致內存泄漏;
2) auto_ptr構造時取得某個對象的控制權,在析構時釋放該對象。我們實際上是創(chuàng)建一個auto_ptr<type>類型的局部對象,該局部對象析構時,會將自身所擁有的指針空間釋放,所以不會有內存泄漏;</type>
3) auto_ptr的構造函數是explicit,阻止了一般指針隱式轉換為 auto_ptr的構造,所以不能直接將一般類型的指針賦值給auto_ptr類型的對象,必須用auto_ptr的構造函數創(chuàng)建對象;
4) 由于auto_ptr對象析構時會刪除它所擁有的指針,所以使用時避免多個auto_ptr對象管理同一個指針;
5) Auto_ptr內部實現,析構函數中刪除對象用的是delete而不是
剩余60%內容,訂閱專欄后可繼續(xù)查看/也可單篇購買
- 本專欄成功幫助阿秀拿到字節(jié)跳動SP的offer,脫胎于個人秋招時期的筆記總結。其中收納C++(217道)、操作系統(62道)、計算機網絡(100道)、數據結構與算法、數據庫(MySQL、Redis)等高頻問答知識點。 - 本專欄適合于校招、社招等找工作黨,后來逐漸收錄一些學弟學妹的上岸經驗和方法,歡迎訂閱,持續(xù)更新ing。