Interface (entête) du pimpl :
#pragma once #include <memory> class Fridge { public: Fridge(); Fridge(const Fridge& other) = delete; Fridge(Fridge&&); Fridge& operator=(const Fridge& other) = delete; Fridge& operator=(Fridge&&); ~Fridge(); void coolDown(); private: class FridgeImpl; std::unique_ptr<FridgeImpl> impl_; };
Implémentation (source) :
#include "Fridge.h" #include <iostream> class Fridge::FridgeImpl { public: void coolDown() { std::cout << "coucou\n"; } private: int engine_; }; Fridge::Fridge() : impl_(new FridgeImpl()) {} Fridge::Fridge(Fridge&&) = default; Fridge& Fridge::operator=(Fridge&&) = default; Fridge::~Fridge() = default; void Fridge::coolDown() { impl_->coolDown(); }
GotW #100: Compilation Firewalls Archive du 27/11/2011 le 07/11/2019
Pourquoi tout ça ?
#include <memory> class A { private: struct Aimpl; std::unique_ptr<Aimpl> impl; }; int main() { auto p = std::make_unique<A>(A{}); }
Erreur : error: invalid application of 'sizeof' to incomplete type 'A::Aimpl'.
Il faut empêcher de mettre inline le constructeur et le destructeur.
#include <memory> class A { public: A(); ~A(); private: struct Aimpl; std::unique_ptr<Aimpl> impl; }; int main() { auto p = std::make_unique<A>(A{}); }
Erreur : copy constructor of 'A' is implicitly deleted because field 'impl' has a deleted copy constructor.
Ajout du constructeur et de l'opérateur move.
#include <memory> class A { public: A(); ~A(); A(A&&) = default; A& operator=(A&&) = default; private: struct Aimpl; std::unique_ptr<Aimpl> impl; }; int main() { auto p = std::make_unique<A>(A{}); }
Erreur : invalid application of 'sizeof' to incomplete type 'A::Aimpl'.
Même problème que Version 2. Il faut enlever le inline au constructeur et à l'opérateur move.
#include <memory> class A { public: A(); A(A&&); A& operator=(A&&); ~A(); private: struct Aimpl; std::unique_ptr<Aimpl> impl; }; int main() { auto p = std::make_unique<A>(A{}); }
Il faut bien sûr implémenter A::A(), A::~A(), A::A(A&&), A& A::operator=(A&&) dans le .cpp.