欧美1区2区3区激情无套,两个女人互添下身视频在线观看,久久av无码精品人妻系列,久久精品噜噜噜成人,末发育娇小性色xxxx

面試真題 | B站C++渲染引擎

一、基礎(chǔ)與語法

  1. 自我介紹

    • 請簡要介紹自己的背景、專業(yè)技能和工作經(jīng)驗。
  2. 實習(xí)介紹

    • 詳細(xì)描述你在實習(xí)期間參與的項目、職責(zé)和成果。

二、智能指針相關(guān)問題回答

unique_ptr 是如何實現(xiàn)的?它有哪些特點和優(yōu)勢?

unique_ptr 是C++11引入的一種智能指針,用于管理動態(tài)分配的內(nèi)存資源。其實現(xiàn)基于獨占所有權(quán)的概念,即每個 unique_ptr 實例擁有對其所指向?qū)ο蟮奈ㄒ凰袡?quán)。

特點

  1. 獨占所有權(quán):在任何給定的時刻,只能有一個 unique_ptr 實例管理特定的內(nèi)存資源。這確保了內(nèi)存資源的安全性和唯一性。
  2. 自動釋放內(nèi)存:當(dāng) unique_ptr 超出作用域或被重新賦值時,它所管理的內(nèi)存會自動釋放,從而避免了內(nèi)存泄漏的問題。
  3. 指針語義unique_ptr 的使用方式與原始指針相似,可以通過指針操作符(->)和解引用操作符(*)來訪問所指向?qū)ο蟮某蓡T。

優(yōu)勢

  1. 安全性:通過獨占所有權(quán)和自動釋放內(nèi)存的特性,unique_ptr 提供了比原始指針更高的安全性。
  2. 易用性unique_ptr 的使用方式簡單直觀,減少了手動管理內(nèi)存帶來的復(fù)雜性和出錯率。
  3. 性能:由于 unique_ptr 不需要維護(hù)引用計數(shù),因此在某些情況下,它的性能可能比 shared_ptr 更高。

shared_ptr 是如何實現(xiàn)的?它如何實現(xiàn)資源共享和自動管理?

shared_ptr 是C++11引入的另一種智能指針,用于管理動態(tài)分配的內(nèi)存資源,并允許多個指針共享同一個資源。

實現(xiàn)

shared_ptr 的實現(xiàn)基于引用計數(shù)的技術(shù)。每個 shared_ptr 對象都會維護(hù)一個引用計數(shù)器,用于記錄有多少個指針指向同一個對象。當(dāng)引用計數(shù)器為0時,表示沒有任何指針指向該對象,此時會自動釋放該對象的內(nèi)存空間。

資源共享和自動管理

  1. 共享所有權(quán):多個 shared_ptr 實例可以同時指向同一個對象,并共享對所指向?qū)ο蟮乃袡?quán)。這通過引用計數(shù)器來實現(xiàn),每次復(fù)制或賦值 shared_ptr 時,引用計數(shù)器都會增加。
  2. 自動釋放內(nèi)存:當(dāng)最后一個指向?qū)ο蟮?shared_ptr 超出作用域或被重新賦值時,引用計數(shù)器會減為0,此時會自動釋放所管理的內(nèi)存資源。

shared_ptr 是否線程安全?為什么?(計數(shù)器是線程安全的,但指針本身不是)

shared_ptr 的引用計數(shù)器是線程安全的,這意味著在多線程環(huán)境中,多個線程可以安全地同時訪問和修改同一個 shared_ptr 的引用計數(shù)器。然而,shared_ptr 的指針本身并不是線程安全的。

線程安全性

  1. 引用計數(shù)器線程安全shared_ptr 的實現(xiàn)通常會使用原子操作或互斥鎖來保護(hù)引用計數(shù)器的訪問和修改,從而確保線程安全。
  2. 指針本身非線程安全:雖然引用計數(shù)器是線程安全的,但 shared_ptr 所管理的對象指針本身并不是線程安全的。如果多個線程同時訪問和修改同一個對象,需要額外的同步機(jī)制來確保線程安全。

面試官追問

  1. 追問一unique_ptrshared_ptr 在性能上有何差異?

    • 回答unique_ptr 通常比 shared_ptr 性能更高,因為它不需要維護(hù)引用計數(shù)。而 shared_ptr 需要維護(hù)引用計數(shù),并在每次復(fù)制或賦值時進(jìn)行原子操作或互斥鎖保護(hù),這會增加一定的開銷。然而,在需要共享所有權(quán)的場景中,shared_ptr 是更好的選擇,因為它可以自動管理內(nèi)存并避免內(nèi)存泄漏。
  2. 追問二:如何解決 shared_ptr 的循環(huán)引用問題?

    • 回答:循環(huán)引用是指兩個或多個對象相互持有 shared_ptr,形成一個循環(huán)鏈,導(dǎo)致引用計數(shù)永遠(yuǎn)不會變?yōu)?,從而引發(fā)內(nèi)存泄漏。為了解決這個問題,可以使用 weak_ptrweak_ptr 是一種不增加引用計數(shù)的智能指針,它只觀察對象而不擁有對象。通過 weak_ptr,可以破壞循環(huán)引用鏈,讓所有的 shared_ptr 都能夠正常析構(gòu)并釋放所管理的內(nèi)存。
  3. 追問三:在什么情況下應(yīng)該使用 unique_ptr 而不是 shared_ptr?

    • 回答:在以下情況下應(yīng)該使用 unique_ptr 而不是 shared_ptr
      1. 當(dāng)只有一個所有者需要管理內(nèi)存資源時,使用 unique_ptr 可以提供更高的安全性和性能。
      2. 當(dāng)不希望多個指針共享同一個資源時,使用 unique_ptr 可以避免不必要的引用計數(shù)開銷。
      3. 當(dāng)對象的生命周期與單個所有者的生命周期緊密相關(guān)時,使用 unique_ptr 可以更直觀地表達(dá)這種關(guān)系。

三. 虛函數(shù)與構(gòu)造函數(shù)/析構(gòu)函數(shù)

  • 在構(gòu)造函數(shù)中調(diào)用虛函數(shù)會發(fā)生什么?

    在構(gòu)造函數(shù)中調(diào)用虛函數(shù)會導(dǎo)致靜態(tài)綁定(也稱為早綁定),而不是動態(tài)綁定(晚綁定)。這意味著即使虛函數(shù)在派生類中被重寫,在基類的構(gòu)造函數(shù)中調(diào)用該虛函數(shù)時,調(diào)用的仍然是基類中的版本。這是因為在對象構(gòu)造過程中,派生類的部分還沒有被完全構(gòu)造,對象的實際類型(即派生類類型)還沒有完全形成,因此無法正確調(diào)用派生類中的虛函數(shù)版本。

    示例代碼:

    class Base {
    public:
        Base() {
            VirtualFunction(); // 調(diào)用的是 Base::VirtualFunction
        }
        virtual void VirtualFunction() {
            std::cout << "Base class virtual function" << std::endl;
        }
    };
    
    class Derived : public Base {
    public:
        void VirtualFunction() override {
            std::cout << "Derived class virtual function" << std::endl;
        }
    };
    
    int main() {
        Derived d; // 構(gòu)造 Derived 對象時,Base 的構(gòu)造函數(shù)中調(diào)用的是 Base::VirtualFunction
        return 0;
    }
    
  • 為什么析構(gòu)函數(shù)通常需要設(shè)置為虛函數(shù)?

    析構(gòu)函數(shù)通常需要設(shè)置為虛函數(shù),以確保通過基類指針刪除派生類對象時,能夠正確調(diào)用派生類的析構(gòu)函數(shù),從而避免資源泄漏和未定義行為。如果析構(gòu)函數(shù)不是虛函數(shù),那么通過基類指針刪除派生類對象時,只會調(diào)用基類的析構(gòu)函數(shù),派生類特有的資源不會被正確釋放。

    示例代碼:

    class Base {
    public:
        virtual ~Base() { // 基類析構(gòu)函數(shù)設(shè)置為虛函數(shù)
            std::cout << "Base class destructor" << std::endl;
        }
    };
    
    class Derived : public Base {
    public:
        ~Derived() { // 派生類析構(gòu)函數(shù)
            std::cout << "Derived class destructor" << std::endl;
        }
    };
    
    int main() {
        Base* b = new Derived();
        delete b; // 正確調(diào)用 Derived 的析構(gòu)函數(shù),然后調(diào)用 Base 的析構(gòu)函數(shù)
        return 0;
    }
    

    如果基類析構(gòu)函數(shù)不是虛函數(shù),則只會調(diào)用基類的析構(gòu)函數(shù),派生類的資源不會被釋放:

    class Base {
    public:
        ~Base() { // 基類析構(gòu)函數(shù)不是虛函數(shù)
            std::cout << "Base class destructor" << std::endl;
        }
    };
    
    // Derived 類定義同上
    
    int main() {
        Base* b = new Derived();
        delete b; // 只調(diào)用 Base 的析構(gòu)函數(shù),不會調(diào)用 Derived 的析構(gòu)函數(shù)
        return 0;
    }
    

面試官追問及回答

追問1: 在構(gòu)造函數(shù)中調(diào)用虛函數(shù)的具體影響是什么?

回答: 在構(gòu)造函數(shù)中調(diào)用虛函數(shù)的具體影響是,會導(dǎo)致虛函數(shù)的靜態(tài)綁定(早綁定),即調(diào)用的是當(dāng)前正在構(gòu)造的對象的基類中定義的版本。這可能導(dǎo)致派生類特有的行為不被執(zhí)行,甚至可能產(chǎn)生邏輯錯誤或未定義行為,因為派生類的成員可能還沒有被初始化。

追問2: 如果析構(gòu)函數(shù)不是虛函數(shù),會導(dǎo)致什么問題?

回答: 如果析構(gòu)函數(shù)不是虛函數(shù),當(dāng)通過基類指針刪除派生類對象時,會導(dǎo)致只調(diào)用基類的析構(gòu)函數(shù),而派生類的析構(gòu)函數(shù)不會被調(diào)用。這會導(dǎo)致派生類特有的資源(如動態(tài)分配的內(nèi)存、文件句柄等)沒有被正確釋放,從而產(chǎn)生資源泄漏。此外,如果派生類析構(gòu)函數(shù)中有重要的清理邏輯(如關(guān)閉網(wǎng)絡(luò)連接、解鎖資源等),這些邏輯也不會被執(zhí)行,可能導(dǎo)致程序崩潰或未定義行為。

追問3: 在多繼承的情況下,虛析構(gòu)函數(shù)如何處理?

回答: 在多繼承的情況下,每個有虛函數(shù)的基類都應(yīng)該有一個虛析構(gòu)函數(shù)。如果一個類從多個有虛析構(gòu)函數(shù)的基類繼承,那么該類的析構(gòu)函數(shù)將自動成為虛函數(shù),并且會按照C++的析構(gòu)函數(shù)調(diào)用順序(先調(diào)用派生類的析構(gòu)函數(shù),然后依次調(diào)用各基類的析構(gòu)函數(shù),按照構(gòu)造的反向順序)來調(diào)用所有基類的析構(gòu)函數(shù)。這樣可以確保所有基類特有的資源都被正確釋放。

示例代碼(多繼承):

class Base1 {
public:
    virtual ~Base1() {
        std::cout << "Base1 destructor" << std::endl;
    }
};

class Base2 {
public:
    virtual ~Base2() {
        std::cout << "Base2 destructor" << std::endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    ~Derived() override {
        std::cout << "Derived destructor" << std::endl;
    }
};

int main() {
    Base1* b1 = new Derived();
    delete b1; // 正確調(diào)用 Derived 的析構(gòu)函數(shù),然后依次調(diào)用 Base1 和 Base2 的析構(gòu)函數(shù)
    return 0;
}

四、 內(nèi)存地址問題

class A {
    int a;
    int d;
};

class B {
    int b;
};

class C : public A, public B {
    int b;
};

C* c = new C;
A* a = c;
B* b = c;
  • ab、c 指向的地址是否相同?為什么?

回答

在C++中,對象指針的行為和它們所指向的對象的內(nèi)存布局密切相關(guān)。在你的代碼示例中,類 C 是通過多重繼承從類 A 和類 B 派生出來的。下面是對問題的詳細(xì)分析:

  • 類A類B 各自包含一個 int 成員,假設(shè)每個 int 成員占用4個字節(jié)(實際大小依賴于編譯器和平臺)。
  • 類C 作為 AB 的派生類,也包含一個 int 成員 b。由于 C 通過多重繼承自 AB,類 C 的內(nèi)存布局通常會按如下方式排列(這取決于編譯器的具體實現(xiàn),但大多數(shù)現(xiàn)代編譯器遵循類似規(guī)則):
    • 首先是 A 的成員(ad),假設(shè)每個 int 4個字節(jié),則共8個字節(jié)。
    • 然后是 B 的成員(b),也是4個字節(jié)。
    • 最后是 C 自己獨有的成員(b),也是4個字節(jié)。

所以,假設(shè)沒有對齊或其他編譯器特性干擾,類 C 的對象 c 至少需要 8(A)+ 4(B)+ 4(C獨有)= 16 個字節(jié)。

接下來看指針:

  • C* c = new C;c 是一個指向 C 對象實例的指針,指向?qū)ο蟮钠鹗嫉刂贰?/li>
  • A* a = c;a 是一個指向 A 的指針,并將其初始化為 c。由于 AC 的第一個基類,a 指向的地址與 c 相同。
  • B* b = c;b 是一個指向 B 的指針,并將其初始化為 c。這里 b 指向的地址同樣是 c 的起始地址,但是要通過 B 的視角去訪問對象,實際上,從 C 對象起始地址到 B 的成員 b 會有偏移(跳過 A 的部分),但指針轉(zhuǎn)換僅改變了解釋內(nèi)存的方式,并沒有改變指向的內(nèi)存地址。

因此,a、bc 指向的地址是相同的,因為它們都指向同一個 C 對象。不過,當(dāng)通過 a、bc 訪問成員時,編譯器會根據(jù)它們的類型(A、BC)來解釋該地址處的內(nèi)存內(nèi)容。

面試官追問及回答

追問1: 如果 AB 中各自有多個成員變量,ab 指針訪問的偏移會如何變化?

回答: 如果 AB 中各自有多個成員變量,ab 指針在訪問這些成員時仍然會指向同一個 C 對象的基礎(chǔ)地址。不過,通過 a 訪問 A 的成員時,會基于 A 的布局解釋內(nèi)存;通過 b 訪問 B 的成員時,會基于 B 的布局并考慮 A 的大小作為偏移來解釋內(nèi)存。編譯器會在編譯時處理這些偏移。

追問2: 如果在類 C 中,我們將 int b; 成員移動到類定義的開始位置,那么內(nèi)存布局會發(fā)生什么變化?

回答: 如果將 int b; 成員移動到類 C 的定義開始位置,則 C 的內(nèi)存布局將發(fā)生變化?,F(xiàn)在 C 的內(nèi)存布局會先放置 C 獨有的 int b(4個字節(jié)),然后是 A 的成員(ad,共8個字節(jié)),最后是 B 的成員(b,4個字節(jié))。這種情況下,雖然 c 指針仍然指向 C 對象的起始地址,但通過 ab 訪問時,相對于 c 指針的偏移會不同,因為 AB 的成員在 C 對象中的位置發(fā)生了改變。

追問3: 在多重繼承中,使用虛繼承會對內(nèi)存布局和指針轉(zhuǎn)換產(chǎn)生什么影響?

回答: 在多重繼承中,如果 AB(或兩者)通過虛繼承方式被繼承,那么編譯器會引入一個額外的指針(通常稱為虛基類指針)來管理 AB(或兩者)的實例。這個虛基類指針指向一個包含實際 AB 對象的表(虛基類表),以確保正確訪問。這會導(dǎo)致對象 C 的內(nèi)存布局變得更大,因為需要額外的空間來存儲虛基類指針。在指針轉(zhuǎn)換時,編譯器會通過虛基類指針和虛基類表來處理偏移,確保訪問正確的成員。這可能會增加訪問基類成員的開銷,但避免了由于多重繼承引起的菱形繼承問題(鉆石問題)。

五、STL與數(shù)據(jù)結(jié)構(gòu)

STL 中使用 vector 要注意的問題

內(nèi)存分配與擴(kuò)容策略

在STL中,vector是一個表示可變大小數(shù)組的序列容器,它采用連續(xù)存儲空間來存儲元素,這意味著可以采用下標(biāo)對vector的元素進(jìn)行高效訪問。然而,當(dāng)新元素插入時,如果當(dāng)前內(nèi)存空間無法容納,vector需要進(jìn)行內(nèi)存重新分配和元素復(fù)制。

內(nèi)存分配策略

  • vector在初始化時會分配一定的內(nèi)存空間,這個空間大小通常與元素的類型和容器的初始大小有關(guān)。
  • 當(dāng)元素數(shù)量增加到當(dāng)前內(nèi)存空間無法容納時,會按照特定的擴(kuò)容策略重新分配內(nèi)存。常見的

剩余60%內(nèi)容,訂閱專欄后可繼續(xù)查看/也可單篇購買

C/C++面試必考必會 文章被收錄于專欄

【C/C++面試必考必會】專欄,直擊面試核心,精選C/C++及相關(guān)技術(shù)棧中面試官最愛的必考點!從基礎(chǔ)語法到高級特性,從內(nèi)存管理到多線程編程,再到算法與數(shù)據(jù)結(jié)構(gòu)深度剖析,一網(wǎng)打盡。助你快速構(gòu)建知識體系,輕松應(yīng)對技術(shù)挑戰(zhàn)。希望專欄能讓你在面試中脫穎而出,成為技術(shù)崗的搶手人才。

全部評論

相關(guān)推薦

求各位大佬給點意見,不知道如何選擇。薯薯其實三月底就接了高德的offer,但今天淘天在逼簽并且業(yè)務(wù)leader和HR輪番打電話推薦,讓我很糾結(jié)。字節(jié)和騰訊音樂其實還在等HR面,就先不考慮了,先用來引流。我本身是準(zhǔn)備找后端開發(fā)的崗位,以前有兩段實習(xí)也主要是后端開發(fā)方向的(字節(jié)&amp;amp;amp;華為),然后因為自己比較擅長C++和Golang,就投了相關(guān)的崗位。本身淘天肯定是大于高德的,但是淘天這個崗位是跨端引擎的C++開發(fā),是終端技術(shù)部門,好像有點客戶端的意思,就讓我比較猶豫。下面主要介紹一下兩個公司的具體崗位和業(yè)務(wù)。1.高德地圖,base北京,部門是汽車業(yè)務(wù)中心,崗位是Golang后端開發(fā)工程師。聽介紹主要業(yè)務(wù)是做高德地圖給汽車廠商提供導(dǎo)航SDK的。2.淘天集團(tuán),base杭州,部門是終端技術(shù)團(tuán)隊,崗位是C++研發(fā)工程師。主要業(yè)務(wù)是實現(xiàn)一套跨端框架,然后給客戶端團(tuán)隊使用(實現(xiàn)一套代碼多端運行),聽起來有點偏向客戶端開發(fā),但是是用C++做,并且會用到OpenGL(沒做過OpenGL的工作)。求各位大佬幫忙分析一下,主要是在想客戶端會不會就業(yè)面太窄,并且我之前的經(jīng)歷都是后端,這段實習(xí)換方向會不會不太好。以及秋招繼續(xù)找后端開發(fā)的話,哪段實習(xí)經(jīng)歷幫助會更大一點呢?#暑期實習(xí)offer[話題]# #阿里巴巴# #淘天# #高德# #字節(jié)# #騰訊# #牛客AI配圖神器#
投遞淘天集團(tuán)等公司10個崗位
點贊 評論 收藏
分享
評論
4
25
分享

創(chuàng)作者周榜

更多
??途W(wǎng)
牛客企業(yè)服務(wù)