web-dev-qa-db-fra.com

Comment initialiser un shared_ptr qui est membre d'une classe?

Je ne suis pas sûr d'un bon moyen d'initialiser un shared_ptr Qui est membre d'une classe. Pouvez-vous me dire si la façon dont je choisis dans C::foo() est bonne, ou existe-t-il une meilleure solution?

class A
{
  public:
    A();
};

class B
{
  public:
    B(A* pa);
};

class C
{
    boost::shared_ptr<A> mA;
    boost::shared_ptr<B> mB;
    void foo();
};

void C::foo() 
{
    A* pa = new A;
    mA = boost::shared_ptr<A>(pa);
    B* pB = new B(pa);
    mB = boost::shared_ptr<B>(pb);
}
36
Igor Oks

Votre code est tout à fait correct (cela fonctionne), mais vous pouvez utiliser la liste d'initialisation, comme ceci:

C::C() :
  mA(new A),
  mB(new B(mA.get())
{
}

Ce qui est encore plus correct et aussi sûr.

Si, pour une raison quelconque, new A Ou new B Lance, vous n'aurez aucune fuite.

Si new A Est lancé, aucune mémoire n'est allouée et l'exception annule également votre constructeur. Rien n'a été construit.

Si new B Se lève et que l'exception abandonne toujours votre constructeur: mA sera détruit correctement.

Bien sûr, comme une instance de B nécessite un pointeur vers une instance de A, l'ordre de déclaration des membres importe.

L'ordre de déclaration des membres est correct dans votre exemple, mais s'il était inversé, votre compilateur se plaindrait probablement de mB d'être initialisé avant mA et l'instanciation de mB serait probablement échouer (puisque mA ne serait pas encore construit, donc appeler mA.get() invoque un comportement non défini).


Je suggérerais également que vous utilisiez un shared_ptr<A> Au lieu d'un A* Comme paramètre pour votre constructeur B (if cela a du sens et si vous peut accepter les petits frais généraux). Ce serait probablement plus sûr.

Peut-être est-il garanti qu'une instance de B ne peut pas vivre sans une instance de A et alors mon conseil ne s'applique pas, mais nous manquons de contexte ici pour donner un conseil définitif à ce sujet .

30
ereOn