2008-09-24 6 views

Antwort

45

Alles, was Sie tun müssen, ist die Klasse private neuen Betreiber:

class X 
{ 
    private: 
     // Prevent heap allocation 
     void * operator new (size_t); 
     void * operator new[] (size_t); 
     void operator delete (void *); 
     void operator delete[] (void*); 

    // ... 
    // The rest of the implementation for X 
    // ... 
}; 

Herstellung ‚erklären Betreiber neue‘ Private verhindert effektiv Code außerhalb der Klasse verwenden ‚neuen‘ eine Instanz von X erstellen

Um die Dinge abzuschließen, sollten Sie "Operator löschen" und die Array-Versionen beider Operatoren ausblenden.

Da C++ 11 Sie können explizit löschen auch die Funktionen:

class X 
{ 
// public, protected, private ... does not matter 
    static void *operator new  (size_t) = delete; 
    static void *operator new[] (size_t) = delete; 
    static void operator delete (void*) = delete; 
    static void operator delete[](void*) = delete; 
}; 

Verwandte Frage:Is it possible to prevent stack allocation of an object and only allow it to be instiated with ‘new’?

+3

Ein weiterer Punkt ist, dass dies nur stoppt, wenn "neu" von außerhalb der Klassenhierarchie aufgerufen wird. dh.Es ist möglich, dass ein Mitglied von 'X' die Funktion aufruft. Das neue C++ '0x-Feature "= delete" ermöglicht es Ihnen, explizit zu verhindern, dass die Funktion jemals aufgerufen wird. –

+6

Richard, nein, diese Methoden können niemals aufgerufen werden, da sie nur deklariert, aber nicht definiert sind. Der Unterschied besteht darin, dass der private Zugriff eher einen Linker-Fehler als einen Compiler-Fehler ergibt. –

+1

Das verhindert nicht 'X * x = :: new X;', was explizit den globalen Operator new aufruft, nicht den Klassenoperator new ... –

6

Ich bin von Ihrer Motivation nicht überzeugt.

Es gibt gute Gründe, RAII-Klassen im Free Store zu erstellen.

Zum Beispiel habe ich eine RAII Lock-Klasse. Ich habe einen Pfad durch den Code, wo die Sperre nur notwendig ist, wenn bestimmte Bedingungen erfüllt sind (es ist ein Videoplayer, und ich muss die Sperre nur während meiner Renderschleife halten, wenn ich ein Video geladen und abgespielt habe; wenn nichts geladen ist, Ich brauche es nicht). Die Möglichkeit, Sperren im Free Store (mit einem scoped_ptr/auto_ptr) zu erstellen, ist daher sehr nützlich. es erlaubt mir, denselben Codepfad zu verwenden, unabhängig davon, ob ich das Schloss herausnehmen muss.

also etwa so:

auto_ptr<lock> l; 
if(needs_lock) 
{ 
    l.reset(new lock(mtx)); 
} 
render(); 

Wenn ich nur Sperren auf dem Stapel erstellen konnte, konnte ich das nicht tun ....

+0

Ein interessanter Punkt. Dafür gebe ich dir +1. Beachten Sie jedoch, dass es Situationen gibt, in denen das RAII-Idiom nicht unbedingt optional ist. Wie auch immer, vielleicht ist es eine bessere Möglichkeit, sich Ihrem Dilemma zu nähern, indem Sie Ihrem Lock-Konstruktor einen Parameter hinzufügen, der angibt, ob die Sperre benötigt wird. – Kevin

+0

Zum Beispiel: Klassensperre { Mutex & m; Bool dolock; public: Schloss (Mutex & m_, bool dolock_): m (M_), dolock (dolock_) {if (dolock) m.lock(); } ~ lock() {wenn (dolock) m.unlock(); } }; Dann könnten Sie schreiben: Sperre l (mtx, needs_lock); rendern(); – Kevin

+0

Ich neige dazu, die Route 'extra Parameter' zu nehmen und die Klasse eine optionaleLock zu nennen ... –

2

@DrPizza:

Das ist ein interessanter Punkt, den Sie haben. Beachten Sie jedoch, dass es Situationen gibt, in denen das RAII-Idiom nicht unbedingt optional ist.

Wie auch immer, ein besserer Weg, Ihrem Dilemma zu begegnen, ist, einen Parameter zu Ihrem Lock-Konstruktor hinzuzufügen, der anzeigt, ob die Sperre benötigt wird. Zum Beispiel:

class optional_lock 
{ 
    mutex& m; 
    bool dolock; 

public: 
    optional_lock(mutex& m_, bool dolock_) 
     : m(m_) 
     , dolock(dolock_) 
    { 
     if (dolock) m.lock(); 
    } 
    ~optional_lock() 
    { 
     if (dolock) m.unlock(); 
    } 
}; 

Dann könnten Sie schreiben:

optional_lock l(mtx, needs_lock); 
render(); 
0

In meiner speziellen Situation, wenn die Sperre nicht der Mutex nicht einmal nicht notwendig ist, vorhanden ist, so denke ich, dass Ansatz wäre eher schwerer zu passen.

Ich denke, die Sache, die ich wirklich zu kämpfen habe, ist die Rechtfertigung für das Verbot der Schaffung dieser Objekte im freien Geschäft.

+1

Die Begründung ist, dass dies einfach ein Weg ist, um eine Regel zu erzwingen, so dass der nächste Entwickler, der kommt, nicht versehentlich etwas tut, wie vergessen, eine Sperre zu löschen (was eine Sperre verursachen würde). – Kevin