2010-06-22 12 views
7

So che esistono metodi per impedire la creazione di una classe nello heap, impedendo all'utente di utilizzare l'operatore new e delete. Sto cercando di fare esattamente il contrario. Ho una classe che voglio impedire all'utente di creare un'istanza di esso nello stack e che verranno compilate solo le istanze istigate usando l'operatore new. Più in particolare, voglio il seguente codice per ricevere un errore durante la compilazione:C++, impedendo la creazione di istanze di classe nello stack (durante la compilazione)

MyClass c1; //compilation error 

MyClass* c1 = new MyClass(); //compiles okay 

Dalla ricerca sul web, ho trovato questo suggerimento su come farlo:

class MyClass { 
public: 
    MyClass(); 
private: 
    void destroy() const { delete this; } 

... 

private: 
    ~MyClass(); 
}; 

int main(int argc,char** argv) 
{ 
    MyClass myclass; // <--- error, private destructor called here !!! 

    MyClass* myclass_ptr = new MyClass; 
    myclass_ptr->destroy(); 
} 

Quello che non capisco è perché questo dovrebbe funzionare. Perché dovrebbe essere chiamato il distruttore durante la creazione di un'istanza di MyClass?

+4

dal modo in cui chiamare destrory() come questo ti darà anche un errore del compilatore dato che è dichiarato privato –

+3

Sarei interessato a sapere perché lo vuoi? – log0

+1

vedi la mia altra domanda, che lo spiega a fondo: http: // stackoverflow.it/questions/3095856/prevention-unaligned-data-on-the-heap – eladidan

risposta

21

Quando myclass raggiunge la fine del suo ambito (il prossimo }) il compilatore chiama il distruttore per liberarlo dallo stack. Se il distruttore è privato, tuttavia, non è possibile accedere al distruttore, quindi la classe non può essere posizionata nello stack.

Non mi piace l'aspetto di delete this. In generale, penso che gli oggetti non dovrebbero distruggersi. Forse un modo migliore è quello di avere un costruttore privato per la classe quindi utilizzare una funzione statica per creare un'istanza.

// In class declaration... 
static MyClass* Create() 
{ 
    return new MyClass(); // can access private constructor 
} 

// ... 

MyClass myclass; // illegal, cannot access private constructor 

MyClass* pMyClass = MyClass::Create(); 
delete pMyClass; // after usage 
+1

+1 - invece di scherzare con i distruttori privati ​​usando una variazione del modello singleton è la strada da percorrere –

+15

@Holger: l'unico scopo di un singleton è di consentire _unamente un'istanza_, e questo non lo fa, quindi __it non è affatto un singleton .__ _ Vorrei poter commentare i commenti down._ – sbi

+0

+1 Buono, usando un metodo factory invece di hackerare qualcosa che potrebbe non essere così ovvio per qualcuno che deve usare il tuo codice. – fingerprint211b

12

Perché il distruttore viene chiamato durante la creazione di un'istanza di MyClass?

Non lo è. Deve essere invocato automaticamente quando l'istanza esce dall'ambito, però. Se è privato, il compilatore non deve generare quel codice, quindi l'errore.

Se pensate che facendo il privato distruttore è oscura, un altro modo per limitare una classe per l'allocazione dinamica è quello di rendere tutti i costruttori privati ​​e hanno solo MyClass::create() funzioni che restituiscono oggetti allocati dinamicamente:

class MyClass { 
public: 
    static MyClass* create()    {return new MyClass();} 
    static MyClass* create(const Foo& f) {return new MyClass(f);} 
private: 
    MyClass(); 
    MyClass(const Foo&); 
}; 

Nota che il ritorno puntatori nudi a oggetti che devono essere cancellati è disapprovato. Dovresti invece restituire dei puntatori intelligenti:

class MyClass { 
public: 
    static std::shared_ptr<MyClass> create()    {return new MyClass();} 
    static std::shared_ptr<MyClass> create(const Foo& f) {return new MyClass(f);} 
    // ... 
}; 
+1

-1 per "Se è privato, il compilatore non deve generare quel codice, ..." – berkus

+0

@Berkus: Perdonami? – sbi

+0

Se è privato, può essere chiamato solo dall'ambito della classe interna. Non significa che il compilatore deve o non deve generare codice. – berkus

1

Perché quando l'istanza esce dal campo di applicazione, deve essere distrutta utilizzando il distruttore. Puntatore ad esempio non lo fa.

1

Ogniqualvolta una variabile locale esce dall'ambito, viene distrutta. E sulla distruzione, viene chiamato il distruttore dell'oggetto. Qui, lo scopo è della funzione principale. Quando il programma termina, il distruttore dell'oggetto myclass si chiamerà

1

Non lo è. Il compilatore sta tentando di chiamare il distruttore quando esce dall'ambito e indica la linea di codice che produce questo effetto, che è molto più utile del puntamento alla fine della funzione.

+0

Questo dovrebbe essere un commento (non si risponde affatto alla domanda (principale)). Lo stesso per Pardeep sopra. – n1ckp

+1

La domanda era "Perché il distruttore dovrebbe essere chiamato mentre si crea un'istanza di MyClass?". Questa è una risposta a questa domanda. Impara a leggere prima. – berkus

+1

@Berkus huh? La domanda nel titolo è "C++, impedendo che l'istanza della classe venga creata nello stack (durante la compilazione)". Scusa ma questo NON rispondere a questa domanda. – n1ckp

Problemi correlati