make_unique et de transfert parfait
Pourquoi n'est-il pas std::make_unique
modèle de fonction dans la norme C++11 de la bibliothèque? Je trouve
std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));
un peu verbeux. Ne serait pas la suite être beaucoup plus agréable?
auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);
Ce masque la new
bien et ne mentionne que le type une fois.
De toute façon, voici ma tentative de mise en œuvre de make_unique
:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Il m'a fallu un certain temps pour obtenir le std::forward
choses à compiler, mais je ne suis pas sûr si elle est correcte. S'agit-il? Qu'est-ce exactement ne std::forward<Args>(args)...
veux dire? Que fait le compilateur de cette?
- Assez sûr que nous avons eu cette discussion avant... notez également que
unique_ptr
prend un deuxième paramètre de modèle qui vous devez en quelque sorte permettre - c'est différent deshared_ptr
. - Peut-être que c'est parce qu'il est plutôt facile d'écrire vous-même? Alors qu'un
make_unique()
simplement roulés unnew
déclaration, ce n'est pas commemake_shared()
qui n'est pas trivial à mettre en œuvre correctement (il alloue de l'espace pour le compte de référence et l'objet en même temps). Mais bon question de bien. - Je ne pense pas qu'il serait judicieux de paramétrer
make_unique
avec une coutume deleter, parce qu'évidemment il alloue via un bon vieuxnew
et doit donc utiliser un bon vieuxdelete
🙂 - C'est vrai. Donc, le projet de
make_unique
serait limitée ànew
allocation... eh bien, c'est très bien si vous voulez écrire, mais je peux voir pourquoi quelque chose comme ça ne fait pas partie de la norme. - En fait, j'aime utiliser un
make_unique
modèle depuis le constructeur destd::unique_ptr
est explicite, et donc il est détaillé au retourunique_ptr
à partir d'une fonction. Aussi, je préfère utiliserauto p = make_unique<foo>(bar, baz)
questd::unique_ptr<foo> p(new foo(bar, baz))
. - Comme alternative, vous pouvez écrire p.reset( nouveau SomeUserDefinedType(1, 2, 3) );
make_unique
est à venir dansC++14
, voir isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting
Vous devez vous connecter pour publier un commentaire.
Herb Sutter, président du C++ comité de normalisation, écrit sur son blog:
Il donne également une mise en œuvre qui est identique à celle donnée par l'OP.
Edit:
std::make_unique
est maintenant partie intégrante de C++14.make_unique
modèle de fonction ne prend pas en soi une garantie d'exception sûr des appels. Il s'appuie sur la convention, que l'appelant utilise. En revanche, la stricte statique type de contrôle (qui est la principale diff entre C++ et C) est construit sur l'idée de application sécurité, via des types. Et pour cela,make_unique
peut être simplement une classe à la place de la fonction. Voir, par exemple, mon blog à partir de Mai 2010. C'est aussi liée à la discussion sur l'Herbe du blog.make_unique
pas exception sûr? Comment en faire une classe de le rendre plus exception sûr? Héritant d'une classe qui n'est pas conçue pour être dérivée ne semble pas être une bonne idée pour moi en tout cas...make_unique
une classe, maintenant, je pense qu'il est préférable de faire une fonction qui produit unmake_unique_t
, la raison, c'est un problème avec le plus pervers analyser :-).make_unique
offre la forte exception de garantie. Ou peut-être vous sont un mélange de l'outil à son usage, dans ce cas n la fonction est exception coffre-fort. Envisagervoid f( int *, int* ){}
, offre clairement leno throw
garantie, mais par votre raisonnement, il n'est pas une exception sûr, car il peut être utilisé à mauvais escient. Pire,void f( int, int ) {}
n'est pas une exception en sécurité!:typedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))
...make_unique
comme par magie confère une exception de sécurité sur le code où il peut être appliqué. désolé, vous ne parviennent pas à me convaincre. comme je le vois aucun des trois points sont valables logique, et ils sont également un peu contradictoires.make_unique
fonction. pourquoi êtes-vous en faisant valoir qu'il devrait être plus risqué?make_unique
mis en œuvre comme ci-dessus et vous m'indiquer un article de Sutter, l'article que mon google-fu m'a indiqué que les étatsmake_unique
offre le fort exception de garantie, ce qui contredit votre affirmation ci-dessus. Si vous avez un autre article que j'ai suis intéressé à le lire. Donc ma question d'origine des peuplements Comment estmake_unique
(tel que défini ci-dessus) ne font pas exception sûr? (Note: oui, je pense quemake_unique
améliore exception de sécurité dans les lieux où il peut être appliqué)make_unique
fonction. D'abord je ne vois pas en quoi c'est dangereux, et je ne vois pas comment l'ajout d'un type supplémentaire serait de le faire sûr. Ce que je sais, c'est que je m'intéresse à comprendre les questions que cette mise en œuvre peut avoir --je ne vois pas tout--, et comment une alternative serait de les résoudre. Quelles sont les conventions quemake_unique
dépend? Comment voulez-vous utiliser la vérification de type à faire respecter la sécurité? Ce sont les deux questions auxquelles j'aimerais une réponse.make_unique
. c'est à propos de l'utilisation d'une fonction déclarée avec deux ou plus de deuxunique_ptr
args.make_unique
est juste un outil que l'utilisateur d'un tel dangereuse la fonction peut utiliser pour faire un appel coffre-fort. l'utilisateur peut aussi le faire dans d'autres façons, mais toujours la fonction est dangereux d'une façon originale: il nécessite une certaine compréhension profonde d'écrire plus de faire des appels en sécurité. au lieu de cela les arguments formels peuvent être de type il faut utilisation demake_unique
, ou explicites, en passant de la propriété des objets existants. ce qui est bien plus robuste.make_unique_t
que les forces de l'utilisation demake_unique
et en interne détient leunique_ptr
pour s'assurer que les appelants est utilisermake_unique
qui est fort. Au départ, j'ai compris que vous avez demandémake_unique
de ne pas être/faire l'appel exception coffre-fort. Concernant ce type supplémentaire, le problème, c'est que vous serez alors restreindre les utilisations de votre fonction de mémoire qui a été allouée, qui permettrait de limiter l'utilisabilité (vous pouvez également fournir unmake_unique
variante qui est capable de se déplacer à partir d'un déjà construitunique_ptr
)make_unique_ptr_t<T>
est le plus naturellement une classe dérivée deunique_ptr<T>
, et puis il a justeunique_ptr<T>
de la classe de base sous-objet et n'ajoute pas possible frais généraux -- c'est à dire, c'est gratuit.Nice, mais Stephan T. Lavavej (mieux connu sous le nom STL) a une meilleure solution pour
make_unique
, qui fonctionne correctement pour le choix de la version.Ceci peut être vu sur son Noyau en C++ 6 vidéo.
Une version mise à jour de la STL version de make_unique est maintenant disponible en N3656. Cette version ai adopté dans le projet de C++14.
make_unique
devrait aller dans un en-tête. Les en-têtes ne devrait pas importer un espace de noms (voir Point n ° 59 de Sutter/Alexandrescu de "C++ Normes de Codification" du livre). Xeo les changements d'aider à éviter d'encourager les mauvaises pratiques.std::make_shared
n'est pas seulement un raccourci pourstd::shared_ptr<Type> ptr(new Type(...));
. Il fait quelque chose qui vous ne peut pas faire sans elle.Afin de faire son travail,
std::shared_ptr
doit allouer un suivi bloc en plus de détenir le stockage pour le pointeur. Cependant, parce questd::make_shared
alloue de l'objet réel, il est possible questd::make_shared
alloue à la fois l'objet et le suivi de bloc dans le même bloc de mémoire.Ainsi, alors que
std::shared_ptr<Type> ptr = new Type(...);
serait de deux allocations de mémoire (un pour lenew
, l'un dans lestd::shared_ptr
suivi bloc),std::make_shared<Type>(...)
serait d'allouer un bloc de mémoire.Qui est important pour de nombreux utilisateurs potentiels de
std::shared_ptr
. La seule chose unstd::make_unique
serait faire est d'être un peu plus pratique. Rien de plus que cela.Alors que rien ne vous empêche de rédiger votre propre helper, je crois que la principale raison de
make_shared<T>
dans la bibliothèque, c'est qu'il crée un autre type interne de pointeur partagé queshared_ptr<T>(new T)
, qui est différemment affectés, et il n'y a aucun moyen d'y parvenir sans l'dédié helper.VotreCorrection: ce n'est pas vrai, en fait: Avoir un appel de fonction pour envelopper lemake_unique
wrapper sur l'autre main est simple sucre syntaxique autour d'unnew
expression, si bien qu'elle puisse être agréable à l'œil, il n'apporte riennew
à la table.new
expression fournit exception de sécurité, par exemple dans le cas où vous appelez une fonctionvoid f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
. Ayant deux premièresnew
s qui sont non séquencés à l'égard l'un de l'autre signifie que si une nouvelle expression échoue avec une exception, les autres peuvent avoir des fuites de ressources. Quant à savoir pourquoi il n'y a pasmake_unique
dans la norme: Il a été tout simplement oublié. (Ce qui arrive de temps en temps. Il n'y a également aucunstd::cbegin
dans la norme, même si il devrait être une).Également noter que
unique_ptr
prend un deuxième paramètre de modèle qui vous devez en quelque sorte permettre; ce qui est différent deshared_ptr
, qui utilise le type d'effacement de magasin personnalisé deleters sans faire partie de la type.shared_ptr<T>(new T)
utilise l'un d'eux,make_shared<T>()
utilise un autre. Permettant que c'est une Bonne Chose, et la version partagée est dans un certain sens le plus léger de poids pointeur partagé que vous pouvez obtenir.shared_ptr
. Si vous passez le pointeur de façon explicite, il a besoin de la création d'un "nouveau" bloc, si vous utilisezmake_shared
il peut bundle votre de l'objet et le satellite de données dans un seul bloc de mémoire (unnew
) ce qui accélère l'allocation/désallocation, moins de fragmentation, et (normalement) un meilleur comportement du cache.unique_ptr
est beaucoup plus léger de classe -- je dirais quemake_shared
est aussi proche de la notion deunique_ptr
que vous pouvez obtenir, mais seulement qu'il utilise un allocateur plutôt que de laisser l'utilisateur choisir la fonction d'allocation.En C++11
...
est utilisé (dans le modèle de code) pour le "pack d'extension" trop.La condition est que vous l'utiliser comme un suffixe d'une expression contenant un non développés pack de paramètres, et il sera tout simplement appliquer l'expression de chacun des éléments du pack.
Par exemple, la construction de votre exemple:
Le dernier étant incorrect, je pense.
Également, pack d'arguments peut pas être transmis à une fonction non développés. Je ne suis pas sûr au sujet d'un paquet de paramètres du modèle.
std::forward<Args>(args)...
, qui s'étend àforward<T1>(x1), forward<T2>(x2), ...
.T1
... serait venu de nulle part.forward
fait toujours besoin d'un paramètre du modèle, n'est-ce pas?std::forward
, il ne compile pas. Il a été conçu à l'erreur dans cette voie.make_unique
dans votre exemple.Inspiré par la mise en œuvre par Stephan T. Lavavej, j'ai pensé qu'il pourrait être sympa d'avoir un make_unique que pris en charge tableau des extensions, c'est sur github et j'aimerais obtenir des commentaires sur elle. Il vous permet de le faire: