utiliser un suppresseur personnalisé
Le problème est que unique_ptr<T>
doit appeler le destructeur T::~T()
dans son propre destructeur, son opérateur d'affectation de mouvement, et unique_ptr::reset()
fonction membre (uniquement). Cependant, elles doivent être appelées (implicitement ou explicitement) dans plusieurs situations PIMPL (déjà dans le destructeur de la classe externe et l'opérateur d'affectation de déplacement).
Comme déjà souligné dans une autre réponse, une façon d'éviter cela est de déplacer tous les opérations qui nécessitent unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
et unique_ptr::reset()
dans le fichier source où la classe d'aide pimpl est réellement définie.
Cependant, cela est plutôt gênant et défie dans une certaine mesure l'objectif même du pimpl idoim. Une solution beaucoup plus propre, qui évite tout cela, consiste à utiliser un fichier suppresseur personnalisé et de ne déplacer sa définition que dans le fichier source où se trouve la classe d'aide du Bourgeon. Voici un exemple simple :
// file.h
class foo
{
struct pimpl;
struct pimpl_deleter { void operator()(pimpl*) const; };
std::unique_ptr<pimpl,pimpl_deleter> m_pimpl;
public:
foo(some data);
foo(foo&&) = default; // no need to define this in file.cc
foo&operator=(foo&&) = default; // no need to define this in file.cc
//foo::~foo() auto-generated: no need to define this in file.cc
};
// file.cc
struct foo::pimpl
{
// lots of complicated code
};
void foo::pimpl_deleter::operator()(foo::pimpl*ptr) const { delete ptr; }
Au lieu d'une classe de suppresseur séparée, vous pouvez également utiliser une fonction libre ou static
membre de foo
en conjonction avec un lambda :
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};
1 votes
Lien de référence pour les exigences de complétude : stackoverflow.com/a/6089065/576911
1 votes
Un pimpl est souvent construit et non modifié depuis. J'utilise habituellement un std::shared_ptr<const window_impl>
0 votes
Relié : J'aimerais beaucoup savoir pourquoi cela fonctionne dans MSVC, et comment l'empêcher de fonctionner (afin de ne pas casser les compilations de mes collègues de GCC).