Почему 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)...
значит? Что компилятор делает из этого?
c++
c++11
variadic-templates
unique-ptr
perfect-forwarding
fredoverflow
источник
источник
unique_ptr
принимает второй параметр шаблона, который вы должны как-то учитывать - это отличается отshared_ptr
.make_unique
с помощью пользовательского удалителя, потому что очевидно, что он выделяется через обычный старыйnew
и, следовательно, должен использовать простой старыйdelete
:)make_unique
будет ограниченоnew
распределением ... ну, если вы хотите написать его, хорошо, но я понимаю, почему что-то подобное не является частью стандарта.make_unique
шаблон, поскольку конструкторstd::unique_ptr
явно, и поэтому он является многословным, чтобы вернутьсяunique_ptr
из функции. Кроме того, я бы лучше использовал,auto p = make_unique<foo>(bar, baz)
чемstd::unique_ptr<foo> p(new foo(bar, baz))
.make_unique
приходит вC++14
см isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meetingОтветы:
Херб Саттер, председатель комитета по стандартизации C ++, пишет в своем блоге :
Он также дает реализацию, которая идентична реализации, данной ОП.
Изменить:
std::make_unique
теперь является частью C ++ 14 .источник
make_unique
Шаблон функции не сама по себе гарантирует исключения в безопасности вызовов. Это основано на соглашении, что вызывающая сторона использует это. Напротив, строгая статическая проверка типов (которая является основной разницей между C ++ и C) основана на идее обеспечения безопасности посредством типов. И для этого,make_unique
может быть просто класс вместо функции. Например, смотрите мою статью в блоге от мая 2010 года. Это также связано с обсуждением в блоге Херба.make_unique
класс, теперь я думаю, что лучше сделать его функцией, которая производит amake_unique_t
, причина этого - проблема с самым извращенным синтаксическим анализом :-).make_unique
предоставляет гарантию исключений. Или, может быть, вы смешиваете инструмент с его использованием, и в этом случае ни одна функция не является безопасной для исключения. Подумайтеvoid f( int *, int* ){}
, четко предлагаетno throw
гарантию, но по вашей линии рассуждений это не исключение безопасности, так как он может быть использован не по назначению. Хуже того,void f( int, int ) {}
не исключение также безопасно !:typedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))
...make_unique
реализована , как описано выше , и вы мне точку на статью Sutter, статьи , что мой Google-фу указал мне на государства , которыеmake_unique
предлагают сильную гарантию исключения , что противоречит вашему заявлению выше. Если у вас есть другая статья , я буду заинтересован в чтении. Итак, мой первоначальный вопрос стоит. Какmake_unique
(как определено выше) не исключение безопасно? (Примечание: да, я думаю, что этоmake_unique
повышает безопасность исключений в местах, где это может быть применено)make_unique
функцию. Во-первых, я не понимаю, как это небезопасно, и не вижу, как добавление дополнительного типа сделает его более безопасным . Что я знаю, так это то, что мне интересно понять проблемы, которые могут возникнуть у этой реализации - я не вижу никаких - и как альтернативная реализация могла бы их решить. Какие конвенции , чтоmake_unique
зависит? Как бы вы использовали проверку типов для обеспечения безопасности? Это два вопроса, на которые я хотел бы получить ответ.Хорошо, но у Стефана Т. Лававея (более известного как STL) есть лучшее решение для
make_unique
, которое работает правильно для версии массива.Это можно увидеть на его видео Core C ++ 6 .
Обновленная версия STL make_unique теперь доступна как N3656 . Эта версия была принята в проект C ++ 14.
источник
make_unique
должна идти в заголовке. Заголовки не должны импортировать пространство имен (см. Пункт № 59 в книге Саттера / Александреску «Стандарты кодирования C ++»). Изменения Xeo помогают избежать поощрения плохой практики.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
. Единственное, что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> &&)
. Наличие двух необработанныхnew
s, которые не упорядочены по отношению друг к другу, означает, что если одно новое выражение завершится неудачно с исключением, другое может привести к утечке ресурсов. Что касается того, почему нетmake_unique
в стандарте: это было просто забыто. (Это иногда случается. Там также нет глобальныхstd::cbegin
значений, хотя они и должны быть.)Также обратите внимание, что
unique_ptr
принимает второй параметр шаблона, который вы должны как-то учесть; это отличается от тогоshared_ptr
, что использует стирание типа для хранения пользовательских удалителей, не делая их частью типа.источник
shared_ptr<T>(new T)
использует один из них,make_shared<T>()
использует другой. Допуская, что это хорошо, и версия make-shared в некотором смысле является самым легким разделяемым указателем, который вы можете получить.shared_ptr
выделяет блок динамической памяти, чтобы вести счет и действие «disposer» при созданииshared_ptr
. Если вы передаете указатель явно, ему нужно создать «новый» блок, если выmake_shared
его используете, он может связать ваш объект и спутниковые данные в один блок памяти (одинnew
), что приведет к более быстрому распределению / освобождению, меньшей фрагментации и (обычно) ) лучшее поведение кеша.В C ++ 11
...
(в коде шаблона) тоже используется для «расширения пакета».Требуется, чтобы вы использовали его в качестве суффикса выражения, содержащего нерасширенный пакет параметров, и оно просто применяет выражение к каждому из элементов пакета.
Например, опираясь на ваш пример:
Последнее неверно, я думаю.
Кроме того, пакет аргументов не может быть передан функции без расширения. Я не уверен насчет пакета параметров шаблона.
источник
std::forward<Args>(args)...
, который расширяется доforward<T1>(x1), forward<T2>(x2), ...
.forward
самом деле всегда требуется параметр шаблона, не так ли?Вдохновленный реализацией Stephan T. Lavavej, я подумал, что было бы неплохо иметь make_unique, который поддерживает экстенты массива, он на github, и я хотел бы получить комментарии к нему. Это позволяет вам сделать это:
источник