偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

抖音C++二面挑戰(zhàn):如何限制對象創(chuàng)建位置的方法?

開發(fā) 前端
在實(shí)際開發(fā)中,諸多場景迫切需要限制對象創(chuàng)建位置。比如在資源管理類中,若期望對象像盡職盡責(zé)的管家,自動管理資源,避免內(nèi)存泄漏,那么將其限制在棧上創(chuàng)建是明智之舉;在一些對靈活性要求極高的場景,如需要動態(tài)創(chuàng)建大量不同大小的對象時,限制對象只能在堆上創(chuàng)建則能更好地滿足需求。

棧上創(chuàng)建對象,猶如在自家規(guī)整有序的倉庫中取用物品,由編譯器自動管理內(nèi)存。其過程迅速高效,就像直接從倉庫近在咫尺的貨架上拿取,無需額外尋找空間,直接在??臻g為對象分配內(nèi)存并調(diào)用構(gòu)造函數(shù),函數(shù)結(jié)束時還會自動調(diào)用析構(gòu)函數(shù)清理內(nèi)存。但??臻g有限,如同倉庫空間大小固定,若對象過多或過大,可能導(dǎo)致棧溢出。而堆上創(chuàng)建對象,則好似在廣闊的外部市場獲取資源,需程序員手動操作。使用 new 運(yùn)算符時,先調(diào)用 operator new 函數(shù)在堆空間搜索、分配內(nèi)存,再調(diào)用構(gòu)造函數(shù)初始化對象。這一過程靈活自由,如同在市場能按需挑選不同大小的場地,但也要求程序員精心管理內(nèi)存,否則易引發(fā)內(nèi)存泄漏,就像在市場租了場地卻忘記歸還,造成資源浪費(fèi)。

在實(shí)際開發(fā)中,諸多場景迫切需要限制對象創(chuàng)建位置。比如在資源管理類中,若期望對象像盡職盡責(zé)的管家,自動管理資源,避免內(nèi)存泄漏,那么將其限制在棧上創(chuàng)建是明智之舉;在一些對靈活性要求極高的場景,如需要動態(tài)創(chuàng)建大量不同大小的對象時,限制對象只能在堆上創(chuàng)建則能更好地滿足需求。那么,具體有哪些方法可以實(shí)現(xiàn)對對象創(chuàng)建位置的精準(zhǔn)限制呢?

Part1引言

在 C++ 的編程世界里,對象創(chuàng)建是構(gòu)建程序大廈的基礎(chǔ)操作,而對象創(chuàng)建又分為靜態(tài)建立(棧上)和動態(tài)建立(堆上)這兩種主要方式 ,它們在內(nèi)存分配和構(gòu)造函數(shù)調(diào)用上存在顯著差異。

先來說說棧上對象創(chuàng)建,當(dāng)我們在代碼塊中定義一個對象時,比如ClassName obj;,這就是在棧上創(chuàng)建對象。棧內(nèi)存就像是一個提前準(zhǔn)備好的儲物箱,由編譯器自動管理。當(dāng)對象被創(chuàng)建時,編譯器會在棧上為其分配一塊連續(xù)的內(nèi)存空間,就像從儲物箱里拿出一塊固定大小的區(qū)域來存放物品一樣。而且,棧上對象的構(gòu)造函數(shù)調(diào)用是自動進(jìn)行的,無需額外的手動操作。在這個對象的生命周期內(nèi),只要其所在的代碼塊沒有結(jié)束,它就一直存在。一旦代碼塊執(zhí)行完畢,對象就會自動銷毀,這時候編譯器會自動調(diào)用析構(gòu)函數(shù)來清理對象占用的內(nèi)存空間,就像把物品從儲物箱中拿走,把空間騰出來一樣,整個過程無需我們操心。

再看看堆上對象創(chuàng)建,它和棧上創(chuàng)建有著明顯的不同。堆內(nèi)存更像是一個大型的自由市場,沒有固定的分配模式,由程序員手動管理。當(dāng)我們使用new操作符創(chuàng)建對象時,例如ClassName* ptr = new ClassName();,首先new操作符會在堆上尋找合適的內(nèi)存空間進(jìn)行分配,這就像是在自由市場里尋找一塊合適的攤位,這個過程相對復(fù)雜,需要花費(fèi)一定的時間。

找到合適的內(nèi)存后,才會調(diào)用構(gòu)造函數(shù)來初始化對象,對這個攤位進(jìn)行布置。而當(dāng)對象使用完畢后,我們需要手動調(diào)用delete操作符來釋放內(nèi)存,即delete ptr;,這一步很關(guān)鍵,如果忘記釋放,就會造成內(nèi)存泄漏,就像在自由市場租了攤位卻不歸還,浪費(fèi)了資源。而且堆上對象的生命周期不受代碼塊的限制,只要不手動釋放,它就會一直占用內(nèi)存。

Part2只能在堆上生成的對象類

在實(shí)際的編程場景中,有時候我們需要對對象的創(chuàng)建位置進(jìn)行精細(xì)控制,比如只能在堆上創(chuàng)建對象。這并非是一個簡單的任務(wù),讓我們一步步來探索實(shí)現(xiàn)的方法。

2.1最初的嘗試:構(gòu)造函數(shù)私有化

當(dāng)我們最初思考如何限制對象只能在堆上創(chuàng)建時,很容易想到將構(gòu)造函數(shù)設(shè)為私有。因?yàn)樵?C++ 中,構(gòu)造函數(shù)是創(chuàng)建對象的關(guān)鍵入口,將其私有化似乎就能阻止在棧上直接創(chuàng)建對象,只能通過new在堆上創(chuàng)建 。比如下面這段代碼:

class OnlyHeap1 {
private:
    OnlyHeap1() {}
public:
    static OnlyHeap1* create() {
        return new OnlyHeap1();
    }
};

然而,這種方法存在一個嚴(yán)重的問題。雖然它確實(shí)阻止了在棧上直接創(chuàng)建對象,但是當(dāng)我們使用new操作符創(chuàng)建對象時,new操作符的執(zhí)行過程分為兩步:第一步是執(zhí)行operator new()函數(shù),在堆空間中搜索合適的內(nèi)存并進(jìn)行分配;第二步是調(diào)用構(gòu)造函數(shù)構(gòu)造對象,初始化這片內(nèi)存空間。而 C++ 提供new運(yùn)算符的重載,其實(shí)是只允許重載operator new()函數(shù),這個函數(shù)僅用于分配內(nèi)存,無法提供構(gòu)造功能 。也就是說,即使我們將構(gòu)造函數(shù)私有化,new操作符在調(diào)用構(gòu)造函數(shù)時仍然會因?yàn)樵L問權(quán)限問題而失敗,所以這種方法并不可行。

2.2析構(gòu)函數(shù)的 “秘密使命”

既然構(gòu)造函數(shù)私有化這條路走不通,我們不妨換個思路,從析構(gòu)函數(shù)入手。在 C++ 中,編譯器在為類對象分配??臻g時,會先檢查類的析構(gòu)函數(shù)的訪問性,其實(shí)不光是析構(gòu)函數(shù),只要是非靜態(tài)的函數(shù),編譯器都會進(jìn)行檢查。如果類的析構(gòu)函數(shù)是私有的,編譯器就無法調(diào)用析構(gòu)函數(shù)來釋放內(nèi)存,也就不會在??臻g上為類對象分配內(nèi)存。這就為我們實(shí)現(xiàn)只能在堆上創(chuàng)建對象提供了一種可行的方法。

class OnlyHeap2 {
public:
    OnlyHeap2() {}
    void destroy() {
        delete this;
    }
private:
    ~OnlyHeap2() {}
};

在這段代碼中,我們將析構(gòu)函數(shù)設(shè)為私有,這樣對象就無法在棧上創(chuàng)建。因?yàn)楫?dāng)我們嘗試在棧上創(chuàng)建對象,比如OnlyHeap2 obj;時,編譯器在對象生命周期結(jié)束時無法調(diào)用私有的析構(gòu)函數(shù),從而導(dǎo)致編譯錯誤。而使用new在堆上創(chuàng)建對象時,由于delete操作是在代碼中顯式調(diào)用的,并且在類的成員函數(shù)destroy中,所以可以訪問私有的析構(gòu)函數(shù)。例如:

OnlyHeap2* ptr = new OnlyHeap2();
ptr->destroy();

不過,這種方法也并非完美無缺。當(dāng)這個類作為基類被繼承時,析構(gòu)函數(shù)通常要設(shè)為virtual,然后在子類重寫,以實(shí)現(xiàn)多態(tài)。但如果析構(gòu)函數(shù)是私有的,就無法在子類中重寫,這會導(dǎo)致繼承和多態(tài)的功能無法正常實(shí)現(xiàn)。

2.3完美方案:protected 的巧妙運(yùn)用

為了解決上述方法中存在的問題,我們可以將析構(gòu)函數(shù)設(shè)為protected。這樣,類外無法直接訪問析構(gòu)函數(shù),對象不能在棧上創(chuàng)建,同時子類可以訪問析構(gòu)函數(shù),能夠滿足繼承和多態(tài)的需求。

class OnlyHeap3 {
protected:
    ~OnlyHeap3() {}
public:
    OnlyHeap3() {}
    static OnlyHeap3* create() {
        return new OnlyHeap3();
    }
    void destroy() {
        delete this;
    }
};

進(jìn)一步優(yōu)化,我們可以將構(gòu)造函數(shù)也設(shè)為protected,然后通過public的static函數(shù)create()來創(chuàng)建對象,destory()函數(shù)來釋放對象。這樣不僅實(shí)現(xiàn)了對象只能在堆上創(chuàng)建,還統(tǒng)一了對象的創(chuàng)建和釋放方式,使代碼更加優(yōu)雅和安全。

class OnlyHeap {
protected:
    OnlyHeap() {}
    ~OnlyHeap() {}
public:
    static OnlyHeap* create() {
        return new OnlyHeap();
    }
    void destory() {
        delete this;
    }
};

使用時,我們只需要調(diào)用create()函數(shù)來創(chuàng)建對象,調(diào)用destory()函數(shù)來釋放對象,例如:

OnlyHeap* ptr = OnlyHeap::create();
// 使用對象
ptr->destory();

通過這種方式,我們成功地實(shí)現(xiàn)了一個只能在堆上生成對象的類,并且解決了繼承和多態(tài)相關(guān)的問題,讓代碼在功能和安全性上都得到了保障。

Part3只能在棧上生成的對象類

與只能在堆上生成對象的類相對應(yīng),在某些編程場景中,我們也需要確保對象只能在棧上生成。實(shí)現(xiàn)這一目標(biāo)的關(guān)鍵在于禁用在堆上創(chuàng)建對象的方式。

我們知道,只有使用new運(yùn)算符,對象才會建立在堆上。因此,只要禁用new運(yùn)算符就可以實(shí)現(xiàn)類對象只能建立在棧上。而new運(yùn)算符在執(zhí)行時,總是先調(diào)用operator new()函數(shù)來分配內(nèi)存,所以我們可以將operator new()設(shè)為私有,這樣在類外就無法調(diào)用該函數(shù),從而不能在堆上分配內(nèi)存,也就無法使用new創(chuàng)建對象。同時,為了保證內(nèi)存釋放操作的一致性,delete對應(yīng)的operator delete()函數(shù)也需要設(shè)為私有。以下是具體的代碼實(shí)現(xiàn):

class StackOnly {
private:
    void* operator new(size_t size) {}
    void operator delete(void* ptr) {}
public:
    StackOnly() {}
    ~StackOnly() {}
};

在這段代碼中,StackOnly類將operator new()和operator delete()設(shè)為私有,當(dāng)我們在類外嘗試使用new創(chuàng)建對象時,例如StackOnly* ptr = new StackOnly();,編譯器會因?yàn)闊o法訪問私有成員函數(shù)而報錯,從而確保對象只能在棧上創(chuàng)建,如StackOnly obj;。通過這種簡單而有效的方式,我們成功地實(shí)現(xiàn)了一個只能在棧上生成對象的類,滿足了特定的編程需求 。

Part4相關(guān)面試題

4.1簡述如何設(shè)計一個只能在堆上創(chuàng)建對象的類

回答:有兩種常見方式。其一,把析構(gòu)函數(shù)設(shè)為私有。編譯器分配棧內(nèi)存時需確認(rèn)能調(diào)用析構(gòu)函數(shù),析構(gòu)函數(shù)私有會阻止其在棧上分配。但需提供如 destroy() 的公有函數(shù)釋放內(nèi)存。其二,將構(gòu)造函數(shù)設(shè)為 protected,并提供公有靜態(tài)創(chuàng)建函數(shù),像 static YourClass* create(),在其中用 new 創(chuàng)建并返回對象指針。

4.2怎樣設(shè)計一個僅允許在棧上創(chuàng)建對象的類

回答:對象用 new 會在堆上創(chuàng)建,其底層依賴 operator new 分配內(nèi)存。把類的 operator new 函數(shù)聲明為私有,外部便無法用 new 創(chuàng)建它的對象,從而對象通常只能在棧上聲明。

4.3將析構(gòu)函數(shù)設(shè)為私有讓對象僅在堆上創(chuàng)建時,用 delete 釋放對象會怎樣?如何正確釋放

回答:用 delete 會編譯出錯,因 delete 需調(diào)用析構(gòu)函數(shù),私有析構(gòu)使其無法訪問。正確做法是類內(nèi)定義類似 void destroy() 的公有函數(shù),在其中用 delete this; 語句或手動處理資源后調(diào)用析構(gòu)函數(shù)(析構(gòu)函數(shù)可訪問情況)釋放堆內(nèi)存。

4.4限制只能在堆上創(chuàng)建對象的類,若被繼承會遇到什么問題,怎么處理

回答:若析構(gòu)函數(shù)私有,子類無法訪問以完成析構(gòu)。通常把基類析構(gòu)函數(shù)改為 protected 解決。其能防棧上創(chuàng)建,子類析構(gòu)函數(shù)也能正常調(diào)用它,保障繼承與多態(tài)場景下,借基類指針釋放堆對象不出錯。

4.5把 operator new 設(shè)為私有讓對象僅棧上創(chuàng)建,為何難以限制其在靜態(tài)存儲區(qū)創(chuàng)建

回答:將 operator new 私有可禁用 new,阻止堆創(chuàng)建。但定義全局或靜態(tài)成員對象時,其在靜態(tài)存儲區(qū)分配內(nèi)存,不走 operator new 流程,故該方法無法阻止類對象于靜態(tài)存儲區(qū)聲明創(chuàng)建。

4.6能否用友元函數(shù)突破限制對象創(chuàng)建位置的限制?

回答:能部分突破。如析構(gòu)函數(shù)私有讓對象僅堆上創(chuàng)建時,聲明特定友元函數(shù)可在外部調(diào)析構(gòu)函數(shù),或用 delete 釋放。不過,這違背限制設(shè)計初衷,友元需謹(jǐn)慎使用,避免破壞類封裝與既定內(nèi)存管理規(guī)則。

4.7限制對象創(chuàng)建位置的機(jī)制,與單例模式的創(chuàng)建邏輯有何相似之處?

回答:單例模式常將構(gòu)造函數(shù)設(shè)為 private 或 protected 防隨意創(chuàng)建,通過靜態(tài)方法按特定邏輯供唯一實(shí)例,類似限制堆上創(chuàng)建用靜態(tài) create 函數(shù)借 new 控制創(chuàng)建的思路,都借限制構(gòu)造途徑,按期望邏輯于指定位置(單例的固定存儲區(qū) / 僅堆上)創(chuàng)建對象。

4.8如何確保一個類的對象只能在指定的內(nèi)存池中創(chuàng)建?

回答:可重載 operator new,令其僅從目標(biāo)內(nèi)存池獲取內(nèi)存。內(nèi)存池存可分配內(nèi)存塊列表,重載版本按對象大小,從列表取對應(yīng)內(nèi)存塊并返回地址,供構(gòu)造函數(shù)初始化對象。也可將構(gòu)造函數(shù)保護(hù)化,配合接收內(nèi)存池指針的靜態(tài)創(chuàng)建函數(shù)達(dá)成目標(biāo)。

4.9如果限制了對象只能在棧上創(chuàng)建,對象需要動態(tài)擴(kuò)容該怎么處理?

回答:可設(shè)計類支持 “移動語義”。必要時,棧上對象可調(diào)用轉(zhuǎn)移資源函數(shù),于堆分配更大內(nèi)存,轉(zhuǎn)移內(nèi)部資源至堆空間,并更新自身成員指向堆內(nèi)存。或提前估算合理?xiàng)?臻g,借自定義內(nèi)存管理結(jié)構(gòu),如棧上存儲固定大小鏈表 / 數(shù)組,按特定規(guī)則復(fù)用空間避免溢出與動態(tài)擴(kuò)容需求。

4.10限制對象創(chuàng)建位置對程序的內(nèi)存碎片問題有幫助嗎?

回答:有幫助。如限制于特定內(nèi)存池創(chuàng)建,能按池管理規(guī)則分配 / 回收內(nèi)存,降低碎片化。僅棧上創(chuàng)建可避免堆碎片化,因棧內(nèi)存連續(xù)分配、自動釋放。僅堆上創(chuàng)建也便于借統(tǒng)一釋放邏輯,像內(nèi)存池或自定義 operator delete 優(yōu)化釋放順序,減少外部碎片。

責(zé)任編輯:武曉燕 來源: 深度Linux
相關(guān)推薦

2025-08-12 02:55:00

2009-08-10 13:34:11

創(chuàng)建C# COM對象

2025-08-12 01:22:00

2025-09-15 02:00:00

2013-05-27 15:38:37

Java對象C++

2010-02-06 10:50:10

C++統(tǒng)計對象個數(shù)

2010-02-03 14:18:44

2010-01-25 09:50:58

C++函數(shù)對象

2022-01-22 07:44:12

抖音PC 版電腦刷抖音

2010-02-05 17:09:19

C++創(chuàng)建Web服務(wù)

2025-08-14 09:19:48

2010-02-04 17:05:53

C++動態(tài)創(chuàng)建對象

2011-07-14 17:37:02

C++面向?qū)ο缶幊趟枷?/a>

2021-06-28 05:19:32

抖音電腦

2025-09-11 01:55:00

2022-06-06 12:19:08

抖音功耗優(yōu)化Android 應(yīng)用

2025-09-01 02:15:00

2010-01-26 15:51:06

C++變量

2020-12-02 09:42:42

PythonApp抖音視頻

2023-09-27 23:24:50

C++鏈表
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號