2008-08-14 39 views
22

有誰知道我可以在平臺無關的C++代碼中防止在堆上創建對象嗎?也就是說,對於一類「富」,我想阻止用戶這樣做:如何防止在堆上創建對象?

Foo *ptr = new Foo; 

,並只允許他們這樣做的:

Foo myfooObject; 

有沒有人有什麼想法?

乾杯,

+2

你爲什麼要這樣做? – 2010-08-19 12:29:14

+0

反過來,讀者也可能會感興趣:http://stackoverflow.com/questions/124880/is-it-possible-to-prevent-stack-allocation-of-an-object-and-only-allow-它將成爲 – kevinarpe 2016-08-16 14:37:15

回答

24

Nick's answer是一個很好的起點,但不完整,因爲你確實需要重載:

private: 
    void* operator new(size_t);   // standard new 
    void* operator new(size_t, void*); // placement new 
    void* operator new[](size_t);  // array new 
    void* operator new[](size_t, void*); // placement array new 

(良好的編碼習慣會建議你也應該重載刪除和刪除[]運營商 - 我想,但因爲他們是不會去把它稱爲是不是真的必要

Pauldoo也是正確的,這不下去聚集在Foo上,雖然它生存的富繼承。你可以做一些模板元編程魔術來幫助防止這種情況,但它不會免於「邪惡的用戶」,因此可能不值得複雜化。記錄應該如何使用以及代碼審查以確保正確使用它們是唯一的方法。

-1

你可以宣佈一個名爲「運營商新的」,這將阻止訪問到的新的正常形態Foo類中的功能。

這是你想要的那種行爲嗎?

7

您可以爲Foo重載新內容並將其設爲私有。這意味着編譯器會呻吟......除非你在Foo內部的堆上創建了Foo的實例。爲了理解這種情況,你可以簡單地不寫Foo的新方法,然後鏈接器會呻吟未定義的符號。

class Foo { 
private: 
    void* operator new(size_t size); 
}; 

PS。是的,我知道這可以很容易地繞開。我真的不推薦它 - 我認爲這是一個壞主意 - 我只是回答這個問題! ;-)

-1

不確定這是否提供了編譯時機會,但是你看看是否爲你的類重載了'new'運算符?

6

我不知道如何做到這一點可靠和可移植的方法..但是..

如果對象是在棧上,那麼你也許可以在構造函數中斷言,'值這'總是接近堆棧指針。如果是這種情況,對象很可能會在堆棧中。

我相信,並不是所有的平臺實現他們的籌碼在同一個方向,所以你可能想要做一個一次性的測試,當應用程序啓動驗證棧的增長,其方式..或者做一些軟糖:

FooClass::FooClass() { 
    char dummy; 
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this); 
    if (displacement > 10000 || displacement < -10000) { 
     throw "Not on the stack - maybe.."; 
    } 
} 
+0

有趣的方法! – hackworks 2010-06-30 04:30:06

+0

我認爲這和假人將永遠是彼此接近,無論他們在堆中還是在堆棧中 – Vargas 2010-07-01 20:29:04

3

@Nick

這可以通過創建從派生或聚集的Foo類來規避。我認爲我的建議(雖然不健全)仍然適用於派生類和聚合類。

E.g:

struct MyStruct { 
    Foo m_foo; 
}; 

MyStruct* p = new MyStruct(); 

在這裏,我已經創建了「富」的實例在堆中,繞過美孚的隱藏新的運營商。

0

您可以將它聲明爲一個接口並更直接地從您自己的代碼中控制實現類。

0

因爲調試頭可以覆蓋運營商新的簽名時,最好使用...簽名作爲一個完整的補救措施:

private: 
void* operator new(size_t, ...) = delete; 
void* operator new[](size_t, ...) = delete; 
0

這可以通過將構造私人和提供一個靜態成員被阻止在堆棧中創建一個對象

Class Foo 
{ 
    private: 
     Foo(); 
     Foo(Foo&); 
    public: 
     static Foo GenerateInstance() { 
      Foo a ; return a; 
     } 
} 

這將使得始終在堆棧中創建對象。

相關問題