сделать уникальный и совершенный пересылка


почему нет std::make_unique шаблон функции в стандартной библиотеке C++11? Я нахожу

std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));

немного многословен. Разве не было бы намного приятнее следующее?

auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);

это скрывает new красиво и только один раз упоминает о типа.

в любом случае, вот моя попытка реализации 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)...));
}

мне потребовалось довольно много времени, чтобы получить std::forward материал для компиляции, но я не уверен, если это правильно. Так ли это? Что именно делает std::forward<Args>(args)... в смысле? Что компилятор делает из этого?

6 211

6 ответов:

Херб Саттер, председатель комитета по стандартизации C++, пишет на своем блог:

что C++11 не включает make_unique Это отчасти недосмотр, и он почти наверняка будет добавлен в будущем.

Он также дает реализацию, которая идентична той, которую дает OP.

Edit:std::make_unique теперь является частью C++14.

приятно, но Stephan T. Lavavej (более известный как STL) имеет лучшее решение для make_unique, который работает правильно для версии массива.

#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)...);
}

Это можно увидеть на его ядро C++ 6 видео.

обновленная версия STL версии make_unique теперь доступна как N3656. Эта версия был принят в проект C++14.

std::make_shared Это не просто стенография для std::shared_ptr<Type> ptr(new Type(...));. Он делает то, что вы не может обойтись без него.

чтобы сделать свою работу,std::shared_ptr необходимо выделить блок отслеживания в дополнение к хранению для фактического указателя. Однако, потому что std::make_shared выделяет фактический объект, возможно, что std::make_shared выделяет оба объекта и блок отслеживания в том же блоке памяти.

пока std::shared_ptr<Type> ptr = new Type(...); будет два выделение памяти (один для new, одно в std::shared_ptr блок слежения), std::make_shared<Type>(...) выделяет один блок памяти.

что важно для многих потенциальных пользователей std::shared_ptr. Единственное, что a std::make_unique хотел сделать, это быть немного более удобным. И ничего больше.

хотя ничто не мешает вам написать свой собственный помощник, я считаю, что основная причина предоставления make_shared<T> в библиотеке это то, что он фактически создает другой внутренний тип общего указателя, чем shared_ptr<T>(new T), который по-разному выделяется, и нет никакого способа достичь этого без выделенного помощника.

код make_unique фантик с другой стороны-это просто синтаксический сахар вокруг new выражение, так что хотя это может выглядеть приятным для глаз, это не принесите что-нибудь new к столу.устранение: это на самом деле не так: имея вызов функции, чтобы обернуть new выражение обеспечивает безопасность исключений, например в случае, когда вы вызываете функцию void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Имея два сырых news, которые не связаны друг с другом, означает, что если одно новое выражение не выполняется с исключением, другое может привести к утечке ресурсов. Что касается того, почему нет make_unique в стандарте: это было просто забыто. (Это происходит иногда. Там также нет глобального std::cbegin в стандарте, хотя должен быть один.)

также обратите внимание, что unique_ptr принимает второй параметр шаблона, который вы должны каким-то образом учитывать; это отличается от shared_ptr, который использует тип стирания для магазине пользовательские deleters, не делая их частью типа.

В C++11 ... используется (в коде шаблона) для "аддон" тоже.

требование заключается в том, что вы используете его в качестве суффикса выражения, содержащего нерасширенный пакет параметров, и он просто применит выражение к каждому из элементов пакета.

например, основываясь на вашем примере:

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)

последнее неверно, я думаю.

кроме того, пакет аргументов не может быть передан в функцию unexpanded. Я не уверен насчет пакета параметров шаблона.

вдохновленный реализацией Stephan T. Lavavej, я подумал, что было бы неплохо иметь make_unique, который поддерживает экстенты массива,это на github и я хотел бы получить комментарии об этом. Это позволяет сделать следующее:

// create unique_ptr to an array of 100 integers
auto a = make_unique<int[100]>();

// create a unique_ptr to an array of 100 integers and
// set the first three elements to 1,2,3
auto b = make_unique<int[100]>(1,2,3);