Ich möchte sicherstellen, dass meine RAII-Klasse immer auf dem Stack zugewiesen wird.
Wie verhindere ich, dass eine Klasse über den "new"-Operator zugewiesen wird?
Ich möchte sicherstellen, dass meine RAII-Klasse immer auf dem Stack zugewiesen wird.
Wie verhindere ich, dass eine Klasse über den "new"-Operator zugewiesen wird?
Alles, was Sie tun müssen, ist, den neuen Operator der Klasse als privat zu deklarieren:
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
// ...
};
Wenn man 'operator new' privat macht, wird verhindert, dass Code außerhalb der Klasse 'new' verwendet, um eine Instanz von X zu erzeugen.
Der Vollständigkeit halber sollten Sie "operator delete" und die Array-Versionen der beiden Operatoren ausblenden.
Seit C++11 können Sie die Funktionen auch explizit löschen:
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: Ist es möglich, die Stack-Allokation eines Objekts zu verhindern und nur zuzulassen, dass es mit "new" instanziiert wird?
Ein weiterer Punkt ist, dass dies nur verhindert, dass "new" von außerhalb der Klassenhierarchie aufgerufen wird, d.h. es ist möglich, dass ein Mitglied von "X" die Funktion aufruft. Mit der neuen C++ '0x-Funktion "=delete" können Sie ausdrücklich verhindern, dass die Funktion jemals aufgerufen wird.
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 zu einem Linker- als zu einem Compiler-Fehler führt.
Dies verhindert nicht, dass X *x = ::new X;
, die explizit den globalen Operator new aufruft, nicht den Klassenoperator new...
Ich bin von Ihrer Motivation nicht überzeugt.
Es gibt gute Gründe, RAII-Klassen im freien Handel zu erstellen.
Ich habe zum Beispiel eine RAII-Sperrklasse. Ich habe einen Pfad durch den Code, wo die Sperre nur notwendig ist, wenn bestimmte Bedingungen halten (es ist ein Videoplayer, und ich muss nur die Sperre während meiner Rendering-Schleife halten, wenn ich ein Video geladen und spielen habe; wenn nichts geladen ist, brauche ich es nicht). Die Möglichkeit, Sperren für den freien Speicher zu erstellen (mit einem unique_ptr
) ist daher sehr nützlich; es ermöglicht mir, denselben Codepfad zu verwenden, unabhängig davon, ob ich das Schloss herausnehmen muss.
d.h. etwa so:
unique_ptr<lock> l;
if(needs_lock)
{
l.reset(new lock(mtx));
}
render();
Wenn ich nur Sperren auf dem Stapel erstellen könnte, könnte ich das nicht tun....
Ein interessanter Punkt. Dafür gebe ich Ihnen +1. Beachten Sie jedoch, dass es einige Situationen gibt, in denen das RAII-Idiom nicht unbedingt optional ist. Wie auch immer, vielleicht ein besserer Weg, um Ihr Dilemma zu nähern ist, um einen Parameter zu Ihrer Sperre Konstruktor, der angibt, ob die Sperre benötigt wird, hinzuzufügen.
Zum Beispiel: class lock { mutex& m; bool dolock; public: lock(mutex& m_, bool dolock_) : m(m_), dolock(dolock_) { if (dolock) m.lock(); } ~lock() { if (dolock) m.unlock(); } }; Dann könnte man schreiben: lock l(mtx, needs_lock); render();
Ein Fall, in dem die Verhinderung new
ist unerlässlich: wenn Ihre RAII-Klasse intern einen statischen Stapel aller lebenden Objekte dieser Klasse unterhält und davon ausgeht, dass Objekte der Klasse in umgekehrter Reihenfolge zerstört werden, in der sie erstellt wurden. Ich verwende dies, um den OpenGL-Status zu erhalten, als Ersatz für das veraltete glPushAttrib
/ glPopAttrib
Funktionen.
@DrPizza:
Das ist ein interessanter Punkt, den Sie ansprechen. Beachten Sie jedoch, dass es einige Situationen gibt, in denen das RAII Idiom nicht unbedingt optional ist.
Wie auch immer, vielleicht ist ein besserer Weg, um Ihr Dilemma zu nähern ist, um einen Parameter zu Ihrer Sperre Konstruktor, der angibt, ob die Sperre benötigt wird hinzufügen. 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();
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.