1. 程式人生 > >C++只在棧或堆上例項化物件

C++只在棧或堆上例項化物件

C++如何讓類物件只能在堆(棧)上分配空間

一般情況下寫一個類都是可以採用new在堆上分配空間,或直接採用 類名+物件名 的方式在棧上分配空間。但有時候,如果想讓一個類只能在棧上或者堆上分配空間,又該怎麼實現呢?

下面分別來介紹如何定義只能在棧上或堆上例項化的類。

注:
1.靜態例項化物件 如 A a;的步驟為:先由編譯器為物件在棧空間分配記憶體,移動棧頂指標,挪出適當的空間,然後在這個空間上呼叫建構函式形成一個物件,在物件使用完之後,呼叫解構函式回收記憶體,棧頂指標減一。
2.動態例項化物件:new操作符,第一步執行operator new()函式在堆上分配一個記憶體,然後呼叫建構函式初始化這片空間。

1.只能在棧上分配類物件
只有使用new運算子,物件才會建立在堆上,因此要禁用new運算子才能只在棧上分配空間。但new操作符是C++內建的,所以必須要先認清一個事實即:new operator總是先呼叫operator new,所以我們只要堆new操作符進行過載,並將它宣告為private的,就能保證不能再使用new例項化物件,如:

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

那麼此時就不能再呼叫new操作符了。

2.只能在堆上例項化物件
容易想到的方法是將建構函式私有化,那麼在類外就不能例項化物件,只能在類內提供一個共有函式使用new運算子返回一個物件,這也是典型的單例模式的由來,但在類外還是不能使用new操作符進行例項化。所以這種方法是行不通的。

所以考慮解構函式的私有化。因在棧上例項化物件之後,物件使用完畢之後自動呼叫解構函式,而new物件後,要手動呼叫delete函式才能執行物件的解構函式。
所以當解構函式被私有化之後,若在棧上例項化物件,編譯器先會檢查該物件的解構函式是否可用,如果不可用,則會報錯。在堆上釋放物件時,若不呼叫delete就不會發現解構函式不可訪問。

這就會引發另外一個問題,使用new操作符在堆上例項化的物件要怎麼析構呢?解決辦法就是,在類中自定義一個公有函式用來銷燬物件,該函式呼叫delete操作符,這樣就可以使用該函式銷燬物件而不是直接使用delete操作符了。
如:

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

};

在此,就可以使用new在堆上建立物件而使用destroy()析構物件了。

注意:採用這種方式後,類A不能用在繼承體系當中。
若A為基類,那麼其解構函式就是virtual的(保證記憶體完全釋放),子類必須要能重寫該解構函式,但子類根本無法訪問他,這是其一。其二,即使子類能夠重寫解構函式,若B是繼承自A的子類,且聲明瞭一個B類的物件b,那麼此時若析構B,基類A不能被正確釋放,導致記憶體洩露。

相關推薦

C++例項物件

C++如何讓類物件只能在堆(棧)上分配空間 一般情況下寫一個類都是可以採用new在堆上分配空間,或直接採用 類名+物件名 的方式在棧上分配空間。但有時候,如果想讓一個類只能在棧上或者堆上分配空間,又該怎麼實現呢? 下面分別來介紹如何定義只能在棧上或堆上例項化

如何讓類物件分配空間?

在C++中,類的物件建立分為兩種,一種是靜態建立,如A a;另一種是動態建立,如A* ptr=new A;1、靜態建立類物件:是由編譯器為物件在棧空間中分配記憶體,是通過直接移動棧頂指標,挪出適當的空間,然後在這片記憶體空間上呼叫建構函式形成一個棧物件。使用這種方法,直接呼叫

C#中類的建立和例項

     C#中,例項化就是建立物件的過程,使用關鍵字new來建立。      在看C#視訊中遇到這麼一個例子,就是更改物件的密碼。我們就通過這個例子來理解一下類的建立和例項化。      1、首先要

c#中用反射的方式例項物件

定義一個類: namespace Example { public class ExampleClass {  public int iID = 0;  public string strName = "";  public ExampleClass()  {   iID

C++函式模板的具體化和例項

C++函式模板----模板例項化、具體化 函式模板是C++新增的一種性質,它允許只定義一次函式的實現,即可使用不同型別的引數來呼叫該函式。這樣可以減小程式碼的書寫複雜度,同時也便於修改。 mark:使用函式模板並不會減少最終可執行程式的大小,因為在呼叫模板函式時,編譯器都根據呼叫時的引數型別進行形影的例項化

C++中區 常量區

原文地址:http://blog.csdn.net/xcyuzhen/article/details/4543264 C++中棧區 堆區 常量區(由一道面試題目而學習) 2009-04-28 21:01   #include<iostream.h> void mai

禁止在例項的類【1】

    設計一個禁止在堆中例項化的類,需要過載operator new和operator delete,並將其設為private。當然,也不是沒有破解的方法,那就是placement new。 // 禁止在堆中例項化物件? // 在堆中例項化物件,需要使用new和dele

.net/c#中的區別及程式碼在中的執行流程詳解

在.NET framework環境下,當我們的程式碼執行時,記憶體中有兩個地方用來儲存這些程式碼。假如你不曾瞭解,那就讓我來給你介紹棧(Stack)和堆(Heap)。棧和堆都用來幫助我們執行程式碼的,它們駐留在機器記憶體中,且包含所有程式碼執行所需要的資訊。 棧負責儲存我們的程式碼執行(或呼叫)路徑,而

java通過反射,需要傳了類名和引數,就可以根據不同引數的構造方法例項物件

轉載自:http://www.jianshu.com/p/69ca44916ebf 程式碼塊 @requires_authorization private Object reflateInstance(String className, Object[] args)th

python中如何統計一個類的例項物件

類中的靜態變數 需要通過類名.靜態變數名 來修改 ;通過物件不能修改 python中如何統計一個類的例項化物件?? 1 class Person: 2 #靜態變數count,用於記錄類被例項化的次數 3 count = 0 4 5

2018-10-15 例項物件 Instantiate與銷燬遊戲物件GameObject.Destroy

  GameObject.Instantiate(Object, Vector3, Quaternion, transform.parent); Quaternion[四元數]:例項化後物件的旋轉情況 Quaternion.identity:無旋轉   &nb

collection.namedtuple例項物件

from collection import namedtuple # human = namedtuple('human', ['name', 'height', 'age', 'sex']) h = human('James', 180, 32, 0) # then you can use h.na

根據字串的形式,自動匯入模組並使用反射找到模組中的類,並例項物件,利用importlib和getattr實現的

例如: auth資料夾下一個SCRF.py檔案,裡面有一個Cors類 class CORS(object): def process_request(self): print('666') auth資料

java反射例項物件

-Class類Java中手動建立的每一個類,在編譯後JVM都會為其建立一個Class類物件,在這個Class類物件中儲存了所建類的資訊。可通過Class類提供的方法為一個類例項化物件,區別與new關鍵字建立物件,前者是在類已經編譯好的情況下,通過指定類名來建立例項化物件,後者

jsp呼叫javaBean方式一(new例項物件)

   1:javabean package cn.mldn.lxh.demo; /**  * javaBean 留給JSP呼叫  *   * @author Administrator  *   */ public class SimpleBean {private Str

java內部類例項物件

package com.lzcc.oop.testpolymorphism; /** * 多型測試 * * @author 包子 * */ public class Person {

反射機制--獲取例項物件

在上一節中(點選開啟連結),獲取到了位元組碼檔案物件,那麼如何獲取該位元組碼檔案對應的Person物件呢?(仍然使用在text包下定義的Person類。) 執行早期的方法: package text; public class ReflectDemo2 { publ

js中 建構函式,原型,和例項物件

1,建構函式建立物件造成的記憶體浪費,和原型的引入 function Person(name,age){ this.name = name; this.age = age; this.introduce = function

介面和抽象類不能例項物件

ArrayList points = new ArrayList(); Iterator i = points.iterator(); points是ArrayList的物件,用points.iterator轉換成迭代器的形式也就是i物件; i是Iterator的引用

MINE筆記-面向物件程式設計,原型鏈的理解,建構函式,原型物件例項物件,prototype 運用

// to do list 建立建構函式,例項化物件,來做面向物件程式設計 // 建立建構函式--原型函式(原型物件) function person(name,age,id){ this.name = name; this.age = age; this.id =id // c