std::unique_ptr incomplète, ce type ne compile pas
Je suis en utilisant le pimpl-idiome avec std::unique_ptr
:
class window {
window(const rectangle& rect);
private:
class window_impl; //defined elsewhere
std::unique_ptr<window_impl> impl_; //won't compile
};
Cependant, je reçois une erreur de compilation concernant l'utilisation d'un type incomplète, sur la ligne 304 en <memory>
:
Invalide application de la
sizeof
" à un type incomplète 'uixx::window::window_impl
'
Pour autant que je sache, std::unique_ptr
devrait pouvoir être utilisé avec un type incomplète. Est-ce un bug de la libc++ ou suis-je en train de faire quelque chose de mal ici?
Post code complet s'il vous plaît. En particulier le modèle des constructeurs.
Le coup de pouce de pointeur intelligent bibliothèque interdire
le code de l'OP posté est code complet pour ce cas d'utilisation. Un fichier composé uniquement de
si ces deux lignes étaient à portée de classe, ce serait OK, à condition que le destructeur est définie par une
C. j'ai fait clair maintenant que les deux lignes sont dans une définition de classe.
Le coup de pouce de pointeur intelligent bibliothèque interdire
boost::unique_ptr
de travailler avec incomplètes types: vous avez eu à utiliser boost::shared_ptr
à la place. Êtes-vous sûr que le C++ de la bibliothèque standard n'ont pas la même restriction?le code de l'OP posté est code complet pour ce cas d'utilisation. Un fichier composé uniquement de
#include <memory>
et ces deux lignes devraient compiler... en supposant unique_ptr
est autorisé à être utilisé avec incomplètes types.si ces deux lignes étaient à portée de classe, ce serait OK, à condition que le destructeur est définie par une
window_impl
est terminée. C'est pourquoi je vous demande. Ici, bien sûr, cela ne fonctionne pas car à ce stade, le destructeur de window_impl
n'est pas connue.C. j'ai fait clair maintenant que les deux lignes sont dans une définition de classe.
OriginalL'auteur | 2012-03-31
Vous devez vous connecter pour publier un commentaire.
Voici quelques exemples de
std::unique_ptr
incomplète types. Le problème réside dans la destruction.Si vous utilisez pimpl avec
unique_ptr
, vous devez déclarer un destructeur:parce que sinon, le compilateur génère un par défaut, et il a besoin d'une déclaration complète de
foo::impl
pour cela.Si vous avez des modèle des constructeurs, alors vous êtes foutu, même si vous n'avez pas de construire la
impl_
membre:À l'espace de noms de champ d'application, à l'aide de
unique_ptr
ne fonctionne pas, soit:puisque le compilateur doit savoir ici comment détruire cette durée statique de l'objet. Une solution de contournement est:
Pouvez-vous s'il vous plaît poster un exemple complet quelque part reproduire l'erreur (pastebin ou ideone ou quoi que ce soit) ?
excellente réponse, juste pour remarque, on peut toujours utiliser le constructeur par défaut/destructeur en plaçant par exemple
foo::~foo() = default;
dans le fichier srcUne façon de vivre avec le modèle des constructeurs serait déclarer, mais de ne pas définir le constructeur dans le corps de la classe, de définir quelque part complet impl définition est vu et instancier explicitement toutes les instanciations.
Pourriez-vous expliquer comment cela peut fonctionner dans certains cas et ne serait pas dans d'autres? J'ai utilisé le pimpl idiome avec un unique_ptr et une classe sans destructeur, et dans un autre projet, mon code ne parvient pas à compiler avec l'erreur OP dit..
OriginalL'auteur Alexandre C.
Comme Alexandre C. mentionné, le problème se résume à
window
's destructeur être définis implicitement dans les endroits où le type dewindow_impl
est encore incomplète. En plus de ses solutions, une autre solution de contournement que j'ai utilisé est de déclarer un Deleter foncteur dans l'en-tête:C'est une bonne solution lorsque vous devez disposer d'une fonction en ligne de définition de la création d'une instance de votre "Foo" type (par exemple une adresse ip statique getInstance" méthode qui fait référence constructeur et le destructeur), et vous ne voulez pas déplacer ces éléments dans un fichier de mise en oeuvre comme @adspx5 suggère.
OriginalL'auteur Fernando Costa Bertoldi
Vous avez probablement certains corps de fonction dans les .h de fichier au sein de la classe qui utilise de type incomplète.
Assurez-vous que l'intérieur de votre .h pour la classe de la fenêtre vous n'avez que déclaration de fonction. Tous les corps des fonctions de la fenêtre doit être dans .fichier cpp. Et pour window_impl ainsi...
Btw, vous devez l'ajouter explicitement le destructeur de déclaration de la classe windows dans votre .h fichier.
Mais vous NE pouvez pas mettre vide dtor corps dans vous fichier d'en-tête:
Doit être d'une simple déclaration:
C'était ma solution. De manière plus concise. Juste avoir votre constructeur/destructeur déclaré dans l'en-tête et défini dans le fichier cpp.
OriginalL'auteur adspx5
utiliser un deleter
Le problème est que
unique_ptr<T>
devez appeler le destructeurT::~T()
dans sa propre destructeur, son opérateur d'assignation de déplacement, etunique_ptr::reset()
fonction membre (uniquement). Toutefois, ceux-ci doivent être appelés (implicitement ou explicitement) dans plusieurs PIMPL situations (déjà à l'extérieur de la classe destructeur et déplacer opérateur d'affectation).Comme l'a déjà signalé dans une autre réponse, un moyen de l'éviter est de déplacer tous des opérations qui nécessitent
unique_ptr::~unique_ptr()
,unique_ptr::operator=(unique_ptr&&)
, etunique_ptr::reset()
dans le fichier source où le pimpl de la classe helper est en fait défini.Cependant, c'est plutôt gênant et défie le point de le pimpl idoim à un certain degré. Une bien meilleure solution qui évite tout ce qui est d'utiliser un personnalisé deleter et ne se déplacent que sa définition dans le fichier source où le bourgeon de la classe helper vie. Voici un exemple simple:
À la place d'un autre deleter classe, vous pouvez également utiliser une fonction libre ou
static
membre defoo
en conjonction avec un lambda:OriginalL'auteur Walter
À ajouter à celui de l'autre, les réponses sur la coutume deleter, dans notre intérieur "utilitaires" la bibliothèque, j'ai ajouté une aide d'en-tête à mettre en œuvre ce modèle commun (
std::unique_ptr
d'un type incomplète, connue seulement de quelques de la TU pour par exemple éviter de longs temps de compilation ou de fournir une opaque poignée de clients).Il fournit à la commune d'échafaudage pour ce modèle: une coutume deleter classe qui invoque un définis à l'externe deleter fonction, un alias de type pour un
unique_ptr
avec cette deleter classe, et une macro pour déclarer la deleter fonction en a TU qui a une définition complète de ce type. Je pense que ce qui a une certaine utilité générale, si elle est ici:OriginalL'auteur Matteo Italia
Peut-être pas la meilleure solution, mais parfois vous pouvez utiliser shared_ptr à la place.
Si bien sûr c'est un peu inutile, mais... comme pour unique_ptr, je vais peut-être attendre 10 ans de plus jusqu'à ce que C++ standard décideurs décident de faire appel lambda comme un deleter.
L'autre côté.
Par votre code, il peut arriver que sur la destruction stade window_impl sera incomplète. Cela pourrait être une raison de comportement indéfini.
Voir ceci:
Pourquoi, vraiment, la suppression d'un type incomplète est un comportement indéterminé?
Donc, si possible, j'aimerais définir une base de l'objet de tous vos objets, avec un destructeur virtuel. Et vous êtes presque bon. Vous juste devez garder à l'esprit que le système s'appel destructeur virtuel pour le pointeur de la souris, de sorte que vous devez définir pour chaque ancêtre. Vous devez également définir la classe de base dans la section héritage virtuel (voir cette pour plus de détails).
OriginalL'auteur Stepan Dyatkovskiy