2015-07-12 13 views
5

So che questa è una domanda molto sciocca sul modello di singleton, ma comunque è la prima scelta dell'intervistatore. Potrebbe farmi sapere in basso snippet di codice.query relativa al comportamento singleton

(1) Dopo aver eliminato l'oggetto singleton perché ancora sono in grado di chiamare il metodo show() e funziona correttamente.

delete obj; 
obj=NULL; 
obj->show(); 

(2) Dopo aver creato oggetto obj1 perché io non sono in grado di stampare il contenuto di acquire_lock e della funzione RELEASE_LOCK anche statment stampa "One Time" verrà stampato una volta e se incrementiamo contatore i allora invece di 2 essa sta stampando solo 1, perché?

Foo *obj1=MySingleton<Foo>::GetInstance(); 

(3) l'utilizzo di unique_ptr con oggetto singleton avrà implicazioni negative.

frammento di codice:

#include <iostream> 
#include <fstream> 
#include <memory> 
#include <string> 

using namespace std; 

static int i; 

class Lock 
{ 
public: 
    Lock(){}; 
    ~Lock(){}; 

    void acquire_lock() 
    { 
     cout<<"aquired lock for class"; 
    } 

    void release_lock() 
    { 
     cout<<"released lock for class"; 
    } 

}; 

class Foo 
{ 
public: 
    void show() 
    { 
     cout<<"\ndone\n"; 
    } 
}; 

template <class T> 
class MySingleton 
{ 
protected: 

    MySingleton() {} 

private: 

    //holds one and only object of MySingleton 
    static T* m_pOnlyOneInstance; 
    MySingleton(const MySingleton <T> &) {}; 
    MySingleton <T> & operator=(const MySingleton <T> &) {}; 
    ~MySingleton() {}; 

public: 

    static T * GetInstance(); 

    void foo() 
    { 
     cout<<"Mohan"; 
    } 
}; 


template <class T> 
T* MySingleton<T>::GetInstance() 
{ 
    Lock lock; 
    if (m_pOnlyOneInstance == NULL) 
    { 
     lock.acquire_lock(); 
     cout<<"one Time"<<endl; 
     i++; 
     if(m_pOnlyOneInstance == NULL) 
     { 
      m_pOnlyOneInstance = new T(); 
     } 
     lock.release_lock(); 
    } 
    return m_pOnlyOneInstance; 
} 

template <class T> T* MySingleton<T> :: m_pOnlyOneInstance=NULL; 

int main() 
{ 
    //std::unique_ptr <Foo> obj (MySingleton<Foo>::GetInstance()); 
    Foo *obj=MySingleton<Foo>::GetInstance();  
    //obj->show(); 
    delete obj; 
    obj=NULL; 
    obj->show(); 
    cout<<"\ncalling again\n"; 
    Foo *obj1=MySingleton<Foo>::GetInstance(); 
    obj1->show(); 
    cout<<"i="<<i; 
    return 1; 
} 

Nota: Il Blocco funzioni correlate sono solo fittizio implementazione.

risposta

0

(1) La chiamata non andrebbe a buon fine se effettivamente utilizzata obj per eseguire la chiamata o all'interno della chiamata.

Prima si chiama a una funzione non virtuale, quindi il puntatore obj non è necessario per trovare la funzione. Il compilatore ha già capito al momento della compilazione quale funzione chiamare.

In secondo luogo, la funzione non accede a nessuna variabile membro della classe, quindi mentre riceve un puntatore che è NULL in realtà non lo utilizza mai.

BTW, sembra che questo codice cerchi di utilizzare il modello MySingleton per trasformare altre classi in singleton, ma in realtà non perché non impedisce di creare copie o creare istanze di oggetti in altri modi, quindi non è un vero singleton. L'unica cosa che fa è sempre restituire lo stesso puntatore.

Altro BTW, la seconda chiamata a MySingleton<Foo>::GetInstance() restituisce una copia di un puntatore che è stato eliminato in precedenza quando è stato effettuato delete obj. obj è stato impostato su NULL dopo l'eliminazione, ma il puntatore originale nel modello MySingleton punta ancora sull'oggetto eliminato, quindi la seconda chiamata a GetInstance restituirà volentieri il puntatore ora non valido.

2
  1. Ricordare che obj->show() equivale a Foo::show(obj). Entrambe le espressioni impostano this sul valore di obj all'interno della funzione membro show. Ora, cosa farebbe impostare this a NULL all'interno di show? Niente, perché non fai mai riferimento a this.
  2. Bene, pensate al motivo per cui dovreste usare il modello singleton in primo luogo - per inizializzare qualcosa al massimo una volta. Quella dichiarazione di stampa "una tantum" si trova nel codice in cui l'oggetto viene istanziato, quindi naturalmente non viene eseguito dopo la prima volta. Guarda la logica di GetInstance. Se un'istanza non esiste, crea un'istanza della classe (in modo disordinato ... ma funziona) e in seguito l'istanza esiste. Altrimenti, non fa nulla.
  3. Questa domanda è molto poco chiara, ma quello che presumo tu voglia dire è "quali sono le implicazioni negative di fare std::unique_ptr<Foo> obj = MySingleton<Foo>::GetInstance();?"Come puoi vedere da per unique_ptr, il suo scopo è quello di assumere la proprietà di una risorsa allocata dinamicamente.Questo è sicuramente non dovuto a oggetti singleton. questo caso) è condiviso da un numero qualsiasi di chiamanti, la classe singleton è l'unica che deve gestire la risorsa istanza, questo è un invariante fondamentale del modello singleton.Se si utilizza unique_ptr, non appena obj esce dallo scope cancellerà automaticamente l'istanza, indipendentemente dal fatto che il programma faccia riferimento all'istanza ora liberata altrove
+0

Grazie per il chiarimento. Per il punto (1) se non settoro ancora il NULL funziona e per il punto (2) se cancelliamo l'oggetto singleton allora ho bisogno di impostare m_pOnlyOneInstance = NULL implementando il metodo di pulizia statico per lo scopo di cancellazione dell'oggetto singleton. – user3522354

+0

(1) Giusto, quella funzione membro non fa mai riferimento a 'this', quindi naturalmente non importa quale valore usi. (2) Sì, altrimenti la funzione 'GetInstance' non ha idea se sia necessario istanziare nuovamente la classe più tardi. Ma una funzione di pulizia statica può essere utilizzata solo quando si è certi che nessun'altra variabile faccia riferimento al singleton, quindi non la consiglierei. – mooiamaduck

+0

Intendete dire che non è necessario fornire una funzione di pulizia statica per eliminare esplicitamente l'oggetto Singleton durante l'uscita dell'applicazione. – user3522354

0

La classe singleton deve avere un costrutto privato o e distruttore. Il distruttore dovrebbe gestire qualsiasi pulizia della memoria quando termina l'ambito del singleton, quindi non è necessario eliminarlo esplicitamente. Potrebbe essere pericoloso eliminarlo quando altri oggetti stanno ancora accedendo al singleton dopo il punto di eliminazione. Si potrebbe ottenere un comportamento indefinito quando si "cancella obj" e "obj = null" poiché l'operatore di assegnazione sovraccarico e il distruttore sono privati.

+0

concordo sul fatto che è necessario pulire il metodo statico all'interno della classe singleton per eliminare l'oggetto ma, come ho chiarito nella mia domanda, si tratta di una questione puramente interrogativa. – user3522354

1

Questo non è un modo corretto per eliminare l'oggetto singleton, è necessario scrivere sotto il metodo per eliminare l'istanza e quindi eseguire il programma.

static void cleanup() 
    { 
     delete m_pOnlyOneInstance; 
     m_pOnlyOneInstance= NULL; 

    } 

Ecco l'output:

blocco aquired per ClassOne Tempo blocco rilasciato per la classe fatto

chiamando di nuovo blocco aquired per ClassOne Tempo blocco rilasciato per la classe fatto i = 2

+0

Grazie a ciò, pulisce correttamente e ora sto ottenendo un output corretto. – user3522354