pImpl mit unique_ptr



  • Hallo zusammen,

    folgendes, ich möchte eine Klasse, die mit pImpl Idiom seine Implementierungsdetails versteckt in einer anderen impl Klasse verwenden. Das pImpl ist dabei über ein unique_ptr gelöst, dafür nehme ich in Kauf, dass die Objekte dann nicht kopierbar sind.

    Wenn ich den Konstruktor über über die Initialisierungsliste aufrufe funktioniert das, aber wenn ich den über den Move Zuweisungsoperator im Konstruktor Body moven möchte, bekomme ich die Fehlermeldung "Can't delete incomplete type". Kann mir jemand erklären warum? Oder ein Stichwort liefern?

    Header Klasse A

    //in the header
    class A
    {
      //public interface
      A()=default;
      A(int i); //just an example
      A(A&&) = default;
      A& operator=(A&&) = default;
    //to avoid problems with incomplete type:
      ~A();
    
      private: 
      struct Impl;
      std::unique_ptr<Impl> pimpl;
    }
    
    //in the source 
    
    struct A::Impl
    {
       int state;
    
       Impl(int i):
         state(i){}
     };
    
    A::~A() = default;
    
    A::A(int i):
    pimpl(std::make_uniqe<Impl>(i)){}
    
    

    Klasse A soll verwendet werden in implementierungsklasse einer zweiten Interface Klasse:

    //Header
    class B
    {
     public:
      B(int state_for_a);
      //to avoid problems with incomplete type:
      ~B();
    private: 
      struct Impl;
      std::unique_ptr<Impl> pimpl;
    }
    

    So gehts

    B::Impl: 
    {
      Impl(int state):
      a(state){}
    
      A a;
    }
    B::~B() = default;
    
    B::B(int state_for_a):
    pimpl(std::make_uniqe<Impl>(state_for_a)){}
    

    Warum geht das nicht:

    B::Impl: 
    {
      Impl(int state):
    {
      a = std::move(A(state)) //Can't delete incomplete type (warning: Löschen eines Zeigers auf den nicht definierten Typ A::Impl. Destruktor wurde nicht aufgerufen 
    }
    
      A a;
    }
    B::~B() = default;
    
    B::B(int state_for_a):
    pimpl(std::make_uniqe<Impl>(state_for_a)){}
    

    Edit:

    Habe auch mal bei A::Impl

    Impl() = default;
    

    hinzugefügt, damit der Standard Konstruktor überhaupt aufgerufen werden kann, geht aber leider auch nicht.



  • @Schlangenmensch sagte in pImpl mit unique_ptr:

    //in the source

    .....
    A::~A() = default;

    Warum hst du das geschrieben? Wende die Antwort auf deine Frage an.



  • https://herbsutter.com/gotw/_100/ für --verbose. Abschnitt ab: "You still need to write the visible class’ destructor yourself and define it out of line in the implementation file"



  • @Schlangenmensch Es geht nicht weil der move-assignment Operator von std::unique_ptr<T> den Destruktor von T aufrufen können muss.
    Und wenn du A& operator=(A&&) = default; im Header File schreibst, was meinst du was dann passiert?



  • @wob sagte in pImpl mit unique_ptr:

    https://herbsutter.com/gotw/_100/ für --verbose. Abschnitt ab: "You still need to write the visible class’ destructor yourself and define it out of line in the implementation file"

    Der existiert. Man kann auch im implementation file default verwenden, dass ist kein Problem.

    @hustbaer sagte in pImpl mit unique_ptr:

    @Schlangenmensch Es geht nicht weil der move-assignment Operator von std::unique_ptr<T> den Destruktor von T aufrufen können muss.
    Und wenn du A& operator=(A&&) = default; im Header File schreibst, was meinst du was dann passiert?

    Danke, natürlich. An der Stelle ist der Destruktor noch nicht bekannt.


Log in to reply