2011-02-10 17 views
14

Ho sentimenti contrastanti su static_cast, poiché è il cast di C++ più sicuro disponibile, ma consente allo stesso tempo conversioni sicure e non sicure, quindi devi conoscere il contesto per dire se è effettivamente sicuro o potrebbe portare a UB (ad es. quando si esegue il casting in una sottoclasse).Viene utilizzato in modo statico_cast?

Quindi perché non c'è un cast esplicito più sicuro? Ecco un esempio, dove potrebbe essere utile. In COM, devono restituire il puntatore di interfaccia come void** ppv, in modo da "avere a" lanciare esplicitamente

*ppv = (IInterface*) this; 

che è stato poi suggerito per essere sostituito da un C più sicuro ++ gettato

*ppv = static_cast<IInterface*>(this); 

Ma ha senso di fare anche un static_cast qui? this è di una classe che deriva da IInterface, e quindi si può semplicemente scrivere

IInterface* p = this; // implicit conversion to base, safe for sure 
*ppv = p; 

o utilizzare un aiutante come

template<class T, class U> 
T implicit_cast(U p) { return p; } 

*ppv = implicit_cast<IInterface*>(this); 

Quindi, è vero che static_cast è a volte usi promiscui e può (dovrebbe?) essere sostituito da questo implicit_cast in alcuni casi, o mi manca qualcosa?

EDIT: So che a cast is required in COM, ma non deve essere static_cast, un cast implicito sarebbe sufficiente.

+1

Nota: vedere http://stackoverflow.com/a/869597 per l'attuazione "diritto" di 'implicit_cast' (e una bella spiegazione). –

risposta

5

In questo caso particolare, credo che sia sempre noto che il casting sarà verso l'alto e che pertanto static_cast dovrebbe essere perfettamente sicuro.

Sembra che l'utilizzo di implicit_cast sia probabilmente più sicuro e consente di selezionare in modo esplicito la classe base a cui si desidera eseguire il cast implicito (che è apparentemente richiesto per COM).

Ho eseguito un test rapido con g ++ e implicit_cast restituisce effettivamente indirizzi diversi per diverse classi di base come previsto.

Si noti tuttavia che, per quanto riguarda la primissima frase, direi che loè in realtà più sicuro di static_cast poiché restituisce null o throw se il cast non può essere completato. Al contrario, static_cast restituirà un puntatore dall'aspetto valido e ti lascerà andare avanti fino a quando il tuo programma non esploderà in futuro, non collegato al cast originale.

programma di test:

#include <iostream> 

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

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

class Foo : public B1, public B2 
{ 
}; 

template<class T, class U> 
T implicit_cast(U p) { return p; } 

int main() 
{ 
    Foo* f = new Foo; 
    void **ppv = new void*; 

    *ppv = implicit_cast<B1*>(f); 
    std::cout << *ppv << std::endl;; 
    *ppv = implicit_cast<B2*>(f); 
    std::cout << *ppv << std::endl;; 

    return 0; 
} 
+0

In effetti, 'dynamic_cast' sarebbe più sicuro di' static_cast', ma non l'ho menzionato perché non l'ho mai visto in realtà usato (ho sentito parlare di un successo nelle prestazioni ma non so quanto sia grande). –

+2

@ 7vies: in Visual C++ ci sono circa 2 mila cicli del processore e il compilatore non ti catturerà se lanci il tuo oggetto COM nel tipo sbagliato - otterrai solo un puntatore nullo durante il runtime. – sharptooth

+0

@sharptooth: Sì, 'dynamic_cast' non è sicuramente l'opzione migliore nel contesto COM. Non sono nemmeno sicuro in quale situazione potrebbe essere una buona opzione - nella maggior parte dei casi può essere sostituito da un polimorfismo run-time o in fase di compilazione che sarebbe più sicuro e più veloce allo stesso tempo. –