2008-08-14 14 views
22

Weiß jemand, wie ich in plattformunabhängigem C++ - Code verhindern kann, dass ein Objekt auf dem Heap erstellt wird? Das heißt, für eine Klasse „Foo“, möchte ich verhindern, dass Benutzer dies zu tun:Wie kann verhindert werden, dass ein Objekt auf dem Heap erstellt wird?

Foo *ptr = new Foo; 

und nur ihnen erlauben, dies zu tun:

Foo myfooObject; 

Hat jemand irgendwelche Ideen?

Cheers,

+2

Warum möchten Sie das tun? –

+0

Die Rückseite, die auch für Leser interessant sein kann: http://stackoverflow.com/questions/124880/is-it-possible-to-prevent-stack-allocation-of-an-object-and-only-allow- es-zu-sein – kevinarpe

Antwort

24

Nick's answer ist ein guter Ausgangspunkt, aber unvollständig, da Sie tatsächlich überlasten müssen:

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 

(Gute-Codierung Praxis würde vorschlagen, Sie auch die Löschüberlasten sollten und löschen [] Operatoren - ich würde, aber da sie nicht bekommen genannt werde es nicht wirklich notwendig.)

Pauldoo ist auch richtig, dass dies nicht aggregiert auf Foo überlebt, obwohl es überleben wird von Foo erbt. Du könntest einige Template-Metaprogrammierungen machen, um dies zu verhindern, aber es wäre nicht immun gegen "böse Nutzer" und daher ist es die Komplikation wahrscheinlich nicht wert. Dokumentation wie es verwendet werden sollte, und Code-Review, um sicherzustellen, dass es richtig verwendet wird, sind die einzige ~ 100% -Methode.

+1

Würde ein privater Konstruktor kombiniert mit einer öffentlichen statischen Factory-Methode (Rückgabewert) dasselbe erreichen? – kevinarpe

+1

@kevinarpe Es hängt davon ab, wie buchstäblich wir die Frage lesen. Der genaue Code 'Foo myfooObject;' aus der Frage würde nicht kompilieren, wenn Sie das getan hätten. Das heißt, ich bevorzuge einen Ansatz, der eher dem entspricht, was Sie vorschlagen, wenn ich versuche zu kontrollieren, wie Objekte erzeugt werden. –

-1

Sie eine Funktion „Operator new“ in der Foo-Klasse namens erklären könnte, die den Zugriff auf die normale Form neuer blockieren würden.

Ist das die Art von Verhalten, die Sie wollen?

7

Sie könnten neu für Foo überladen und es privat machen. Dies würde bedeuten, dass der Compiler stöhnen würde ... es sei denn, Sie erstellen eine Instanz von Foo auf dem Heap innerhalb von Foo. Um diesen Fall zu erfassen, könnten Sie Foo's neue Methode einfach nicht schreiben und dann würde der Linker über nicht definierte Symbole meckern.

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

PS. Ja, ich weiß, dass dies leicht umgangen werden kann. Ich empfehle es wirklich nicht - ich denke, es ist eine schlechte Idee - ich habe nur die Frage beantwortet! ;-)

-1

Nicht sicher, ob dies irgendwelche Möglichkeiten zur Kompilierungszeit bietet, aber hast du schon mal den 'neuen' Operator für deine Klasse überladen?

6

Ich weiß nicht, wie es zuverlässig zu tun und in einer tragbaren Weise .. aber ..

Wenn das Objekt auf dem Stapel ist dann könnten Sie in der Lage sein, innerhalb des Konstruktors zu behaupten, dass der Wert von ' Dies ist immer in der Nähe des Stapelzeigers. Es besteht eine gute Chance, dass das Objekt auf dem Stapel ist, wenn dies der Fall ist.

Ich glaube, dass nicht alle Plattformen ihre Stacks in der gleichen Richtung implementieren, so dass Sie einen einmaligen Test machen möchten, wenn die App zu überprüfen beginnen, welchen Weg des Stapel wächst .. Oder etwas Fudge:

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

Interessante Annäherung! – hackworks

+0

Ich denke, dass diese und dummy immer nahe beieinander sein werden, egal ob sie auf dem Haufen oder im Stapel sind – Vargas

+1

@Vargas - ich stimme nicht zu. 'Dummy' wird immer auf dem Stapel sein, da es sich um eine automatische lokale Variable handelt. Der 'this'-Zeiger kann entweder auf den Stack (wenn FooClass als lokale Variable verwendet wird) oder auf den Heap (wenn FooClass auf dem Heap zugewiesen ist oder in einer Klasse aggregieren, die dann auf dem Heap zugeordnet wird) zeigen. – pauldoo

3

@ Nick

Dies könnte durch die Schaffung einer Klasse umgangen werden, die von leitet oder aggregiert Foo. Ich denke, was ich vorschlage (obwohl es nicht robust ist) würde immer noch für abgeleitete und aggregierende Klassen funktionieren.

Z. B:

struct MyStruct { 
    Foo m_foo; 
}; 

MyStruct* p = new MyStruct(); 

Hier habe ich eine Instanz von 'Foo' auf dem Heap erstellt, Foo versteckte neuen Betreiber zu umgehen.

+0

+1 Netter Trick! Typ Casting kann auch helfen – Viet

0

Sie könnten es als Schnittstelle deklarieren und die Implementierungsklasse direkter aus Ihrem eigenen Code steuern.

0

Da Debug-Header der Bediener neue Signatur außer Kraft setzen kann, ist es am besten, die ... Unterschriften als komplette Abhilfe zu verwenden:

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

dies kann zu, indem Konstrukteure private und Bereitstellen eines statisches Element verhindert werden Erstellen Sie ein Objekt im Stapel

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

Dies wird die Erstellung des Objekts immer im Stapel erstellen.