2011-09-05 6 views
8

Ho guardato su internet e questa discussione cercando una risposta completa di questa situazione che sto affrontando. Ho letto che lanciare puntatori intelligenti su oggetti non è molto intelligente. Voglio solo capire perché sta succedendo. Spiegherò la situazione. Immaginiamo questo semplice gerarchia :Smart Pointers e gestione delle eccezioni

class Foo 
{ 
public: virtual ~Foo() {} 
}; 

typedef tr1::shared_ptr<Foo> SPFoo; 

class FooInherited: public Foo { }; 

typedef tr1::shared_ptr<FooInherited> SPFooInherited; 

E cerchiamo di controllare questo codice di prova:

int main(int argc, char** argv) 
{ 
    try 
    { 
    throw FooInherited(); 
    } 
    catch(const Foo& f) 
    { 
    cout << "Foo& caught!" << endl; 
    } 
    try 
    { 
    throw SPFooInherited(new FooInherited()); 
    } 
    catch(const SPFoo& f) 
    { 
    cout << "SPFoo& caught!" << endl; 
    } 
    return 0; 
} 

tutto viene compilato, ma in fase di esecuzione la seconda try-catch non sarà giustiziati. Qualcuno può spiegarmi perché? Specialmente se linee di codice come funzionano perfettamente in runtime.

void function(const SPFoo& f) 
{ 
} 

... 

SPFooInherited fi(new FooInherited()); 
function(fi); 

Capisco che il problema è che SPFooInherited non eredita da SPFoo (anche se FooInherited eredita da Foo), ma è profondamente vorrebbe sapere qual è il compilatore/RTE fare diversamente dall'esempio funzione di chiamata quando si prende un'eccezione per non essere in grado di risolvere la situazione. È perché il parametro catch non è uguale a un parametro di chiamata di funzione? Perché Foo & funziona e SPFoo no?

Grazie mille in anticipo.

Saluti, Iker.

risposta

13

Come hai detto nella tua domanda, SPFooInherited non è una sottoclasse di SPFoo. Ciò significa che catch(SPFoo const&) non rileverà istanze di SPFooInherited. D'altra parte, FooInherited viene ereditato da Foo, quindi catch(Foo const&) catturerà istanze di FooInherited.

Per capire questo non è necessaria alcuna conoscenza particolare del compilatore o dell'ambiente di esecuzione. È semplicemente una parte della lingua.

Il motivo per cui la chiamata alla funzione funziona è che tr1::shared_ptr dispone di un costruttore non esplicito basato su modelli che consente una conversione implicita in siti di chiamata di funzione.

Cioè: tr1::shared_ptr ha il seguente costruttore:

//Note the lack of explicit 
template<class Y> shared_ptr(shared_ptr<Y> const & r); 

Questo permette un shared_ptr di essere costruito da un diverso tipo di puntatore condiviso. L'implementazione di questo costruttore si basa sulla conversione implicita da FooInherited* a Foo* per archiviare effettivamente il puntatore nello . Se questa conversione implicita non esiste, il codice non verrà compilato e non si verificheranno conversioni non sicure tra shared_ptr e tipi non correlati.

La differenza fondamentale tra la chiamata di funzione e il problema è che le conversioni implicite si verificano nell'inizializzazione di argomenti di funzione, ma un fermo può corrispondere un solo tipo (FooInherited è-una Foo, quindi corrisponderà).

3

Perché SPFoo non è una sottoclasse di SPFooInherited.I blocchi catch catturano solo le cose che si trovano nella loro lista di cattura, o una classe figlio pubblica di ciò che è nella loro lista di cattura. FooInherited eredita da Foo, quindi catturare uno Foo ti consente anche di catturare uno FooInherited. SPFoo e SPFooInherited sono classi completamente diverse e non correlate.