215 votes

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 l' 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 l' 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)... moyenne? Que fait le compilateur?

157voto

user763305 Points 6123

Herb Sutter, président du C++ comité de normalisation, écrit sur son blog:

Que C++11 ne comprend pas make_unique est en partie une supervision, et il sera presque certainement être ajouté dans le futur.

Il donne également une mise en œuvre qui est identique à celle donnée par l'OP.

Edit: std::make_unique fera partie de C++14.

77voto

tominator Points 511

Sympa, mais Stephan T. Lavavej (mieux connu sous le nom STL) a une meilleure solution pour make_unique, ce qui fonctionne correctement pour le choix de la version.

#include <memory>
#include <type_traits>
#include <utility>

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::false_type, Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::true_type, Args&&... args) {
   static_assert(std::extent<T>::value == 0,
       "make_unique<T[N]>() is forbidden, please use make_unique<T[]>().");

   typedef typename std::remove_extent<T>::type U;
   return std::unique_ptr<T>(new U[sizeof...(Args)]{std::forward<Args>(args)...});
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return make_unique_helper<T>(std::is_array<T>(), std::forward<Args>(args)...);
}

Ceci peut être vu sur son Cœur de C++ 6 de la vidéo.

Une version mise à jour de la STL version de make_unique est maintenant disponible en N3656. Cette version fait adopter dans le projet de C++14.

19voto

Kerrek SB Points 194696

Alors que rien ne vous empêche de rédiger votre propre helper, je crois que la principale raison pour la fourniture make_shared<T> dans la bibliothèque, c'est qu'il crée un autre type interne de pointeur partagé qu' shared_ptr<T>(new T), ce qui est différemment affectés, et il n'y a aucun moyen d'y parvenir sans l'dédié helper.

Votre make_unique wrapper sur l'autre main est simple sucre syntaxique autour d'un new expression, si bien qu'elle puisse être agréable à l'œil, il n'apporte rien new de la table. Correction: ce n'est pas vrai, en fait: Avoir un appel de fonction pour envelopper l' new expression fournit exception de sécurité, par exemple dans le cas où vous appelez une fonction void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Avoir deux brutes news 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 pas d' make_unique dans la norme: Il a été tout simplement oublié. (Ce qui arrive de temps en temps. Il n'y a également aucun std::cbegin dans la norme, même si il devrait être une).

Notez aussi que l' unique_ptr prend un deuxième paramètre de modèle qui vous devez en quelque sorte permettre; ce qui est différent de shared_ptr, qui utilise le type d'effacement de magasin personnalisés deleters sans faire partie de la type.

19voto

Nicol Bolas Points 133791

std::make_shared n'est pas juste un raccourci pour std::shared_ptr<Type> ptr(new Type(...));. Il fait quelque chose que 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 qu' std::make_shared alloue de l'objet réel, il est possible qu' std::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 l' new, l'un dans l' std::shared_ptr suivi de bloc), std::make_shared<Type>(...) serait d'allouer un bloc de mémoire.

Ce qui est important pour de nombreux utilisateurs potentiels de l' std::shared_ptr. La seule chose que l' std::make_unique serait faire est d'être un peu plus pratique. Rien de plus que cela.

13voto

Matthieu M. Points 101624

En C++11 ... est utilisé (dans le modèle de code) pour le "pack d'extension".

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 de la meute.

Par exemple, en s'appuyant sur l'exemple:

std::forward<Args>(args)... -> std::forward<int>(1), std::forward<int>(2),
                                                     std::forward<int>(3)

std::forward<Args...>(args...) -> std::forward<int, int, int>(1,2,3)

Ce dernier étant incorrect, je pense.

Aussi, le 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X