web-dev-qa-db-fra.com

Transférer la déclaration avec unique_ptr?

J'ai trouvé utile d'utiliser la déclaration directe des classes en combinaison avec std::unique_ptr comme dans le code ci-dessous. Il compile et fonctionne avec GCC, mais le tout semble plutôt étrange, et je me demande si c'est un comportement standard (c'est-à-dire requis par la norme)? Puisque B n'est pas un type complet lorsque je déclare le unique_ptr.

A.hpp

#include <memory>

class B;

class A {
    std::unique_ptr<B> myptr;
    // B::~B() can't be seen from here
public:
    ~A();
};

A.cpp

#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.

A::~A() = default; // without this line, it won't compile 
// however, any destructor definiton will do.

Je soupçonne que cela a à voir avec le destructeur (et donc la nécessité d'appeler le destructeur de unique_ptr<B>) est défini dans une unité de compilation spécifique (A.cpp).

58
Zyx 2000

C'est explicitement légal. La règle est que les types utilisés pour instancier un modèle dans la bibliothèque standard doivent être complets, sauf autrement spécifié. Dans le cas de unique_ptr, Le §20.7.1/5 indique "[...] Le paramètre de modèle T de unique_ptr peut être un type incomplet."

Certaines opérations sur le pointeur nécessitent un type complet; en particulier, quand l'objet sera réellement détruit (au moins avec le deleter par défaut). Dans votre exemple, par exemple, si A::~A() était en ligne, cela pourrait provoquer des problèmes. (Notez que si vous ne déclarez pas le destructeur vous-même, il sera en ligne. Ce qui va partiellement à l'encontre du but d'utiliser std::unique_ptr.)

59
James Kanze