2010-07-07 3 views
21

Je regardais comment std::tr1::shared_ptr<> fournit la capacité de lancer à bool. J'ai pris dans le passé en essayant de créer un pointeur intelligent qui peut être casté bool comme la solution triviale, à savoirComment shared_ptr <> autorise-t-il en toute sécurité le lancement vers bool?

operator bool() { 
    return m_Ptr!=0; 
} 

finit généralement par être implicitement coulable au type de pointeur (probablement par la promotion de type), ce qui est généralement indésirable. Les implémentations de boost et de Microsoft semblent utiliser une astuce consistant à lancer un unspecified_bool_type(). Quelqu'un peut-il expliquer comment ce mécanisme fonctionne et comment il empêche le moulage implicite au type de pointeur sous-jacent?

+0

Toutes les bonnes réponses, merci. Bon d'être en mesure de mettre un nom à elle aussi - n'avait pas rencontré l'idiotisme de la sécurité avant. –

Répondre

31

La technique décrite dans la question est safe bool idiom.

A partir de C++ 11, cet idiome n'est plus nécessaire. La solution moderne au problème est d'utiliser le mot-clé explicit sur l'opérateur:

explicit operator bool() { 
    return m_Ptr != nullptr; 
} 
+0

Oh, je connaissais l'idiotique bool et j'ai récemment découvert les opérateurs de conversion 'explicit', mais je ne connaissais pas cette petite chose '' null_ptr'. Merci :) –

3

Habituellement, ce qu'il renvoie est un pointeur de membre. Les pointeurs de membre peuvent être traités comme bool mais ne prennent pas en charge la plupart des conversions implicites effectuées par bool.

4

L'astuce fonctionne comme ça. Vous définissez tout cela dans votre type de pointeur intelligent (dans ce cas, shared_ptr):

private: 

    struct Tester 
    { 
    Tester(int) {} // No default constructor 
    void dummy() {} 
    }; 

    typedef void (Tester::*unspecified_bool_type)(); 

public: 

    operator unspecified_bool_type() const 
    { 
    return !ptr_ ? 0 : &Tester::dummy; 
    } 

ptr_ est le pointeur natif dans la classe de pointeur intelligent.

Comme vous pouvez le voir, est un unspecified_bool_typetypedef à un type qui ne peut être accessible par un code externe, puisque Tester est un struct privé. Mais le code appelant peut utiliser cette conversion (implicite) en un type de pointeur et vérifier s'il est nul ou non. Qui, en C++, peut être utilisé comme une expression bool.

+0

Quoi de neuf avec le '## ModelId'? – kennytm

+0

@KennyTM: Désolé, je viens de supprimer cela. – Gorpik

+1

Vous devez fournir des implémentations de '! =' Et '==' pour 'Tester :: unspecified_bool_type' ou vous permettrez des comparaisons sans signification entre les instances de la classe à compiler. –

Questions connexes