Comment puis-je utiliser un custom deleter avec un std::unique_ptr membre?
J'ai une classe avec un unique_ptr membre.
class Foo {
private:
std::unique_ptr<Bar> bar;
...
};
Le Bar est un tiers de la classe qui a une fonction create() et destroy() fonction.
Si je voulais utiliser une std::unique_ptr
avec elle dans un support seule fonction que je pouvais faire:
void foo() {
std::unique_ptr<Bar, void(*)(Bar*)> bar(create(), [](Bar* b){ destroy(b); });
...
}
Est-il un moyen de le faire avec std::unique_ptr
en tant que membre d'une classe?
Vous devez vous connecter pour publier un commentaire.
En supposant que
create
etdestroy
sont libres de fonctions (ce qui semble être le cas de l'OP de l'extrait de code) avec les signatures suivantes:Vous pouvez écrire votre classe
Foo
comme ceRemarquez que vous n'avez pas besoin d'écrire de lambda ou personnalisé deleter ici parce que
destroy
est déjà un deleter.std::unique_ptr<Bar, decltype(&destroy)> ptr_;
Il est possible de le faire proprement à l'aide d'un lambda en C++11 (testé dans G++ 4.8.2).
Compte tenu de cette réutilisables
typedef
:Vous pouvez écrire:
Par exemple, avec un
FILE*
:Avec cela, vous obtenez les avantages d'exception-coffre-fort nettoyage à l'aide de RAII, sans avoir besoin de try/catch bruit.
std::function
dans la définition ou autres choses de ce genre?std::function
. Lambda ou classe personnalisée comme dans acceptées réponse peut être incorporé à la différence de cette solution. Mais cette approche a un avantage dans le cas où vous souhaitez isoler la mise en œuvre dans le module dédié.deleted_unique_ptr<Foo> foo(new Foo(), customdeleter);
sicustomdeleter
suit la convention (void et accepte raw pointeur en argument).Vous suffit de créer un deleter classe:
et fournir aussi l'argument de modèle de
unique_ptr
. Vous aurez encore à initialiser le unique_ptr dans votre constructeurs:Autant que je sache, tous les populaire de bibliothèques c++ mettre en œuvre correctement; depuis
BarDeleter
n'ont pas réellement de tout état, il n'a pas besoin d'occuper tout l'espace dans launique_ptr
.struct BarDeleter
) àstd::unique_ptr
(std::unique_ptr<Bar, BarDeleter>
) qui permet à l'std::unique_ptr
constructeur créer un Deleter exemple sur son propre. j'.e le code suivant est autoriséstd::unique_ptr<Bar, BarDeleter> bar[10];
typedef std::unique_ptr<Bar, BarDeleter> UniqueBarPtr
Sauf si vous avez besoin d'être capable de changer la deleter au moment de l'exécution, je vous recommande fortement de l'aide personnalisée deleter type. Par exemple, si l'utilisation d'un pointeur de fonction pour votre deleter,
sizeof(unique_ptr<T, fptr>) == 2 * sizeof(T*)
. En d'autres termes, la moitié des octets de launique_ptr
objet sont gaspillées.Écrit une coutume deleter pour envelopper chaque fonction est une peine, même si. Heureusement, nous pouvons écrire un type basé sur un modèle de la fonction:
Depuis C++17:
Avant C++17:
Vous le savez, à l'aide d'un custom deleter n'est pas la meilleure façon d'aller, comme vous devez le mentionner dans votre code.
Au lieu de cela, comme vous êtes autorisé à ajouter des spécialisations à l'espace de noms de classes de niveau dans
::std
aussi longtemps que les types personnalisés sont impliqués et vous le respect de la sémantique, faire:Se spécialisent
std::default_delete
:Et peut-être aussi ne
std::make_unique()
:std
ouvre une toute nouvelle boîte de pandore. Notez également que la spécialisation destd::make_unique
n'est pas autorisée après C++20 (donc ne devrait pas être fait avant) parce que le C++20 n'autorise pas la spécialisation des choses dansstd
qui ne sont pas des modèles de classe (std::make_unique
est un modèle de fonction). Notez que vous aurez également probablement jusqu'à la fin avec UB si le pointeur passé enstd::unique_ptr<Bar>
n'a pas été alloué decreate()
, mais à partir d'une autre fonction d'allocation.std::default_delete
répond aux exigences du modèle d'origine. J'imagine questd::default_delete<Foo>()(p)
serait un moyen valable pour écriredelete p;
, donc sidelete p;
serait valable pour écrire (c'est à dire siFoo
est complet), ce ne serait pas le même comportement. En outre, sidelete p;
était invalide à écrire (Foo
est incomplète), ce serait de la spécification de nouveaux comportements pourstd::default_delete<Foo>
, plutôt que de garder le comportement identique.Vous pouvez simplement utiliser
std::bind
avec votre détruire fonction.Mais bien sûr, vous pouvez également utiliser une lambda.