¿Por qué 'make unique' no está permitido?
Asuma el espacio de nombres std
a lo largo.
El borrador del comité C++14 N3690 define std::make_unique
así:
[n3690: 20.9.1.4]:
unique_ptr
creación [único.ptr.crear]
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
1 Observaciones: Esta función no participará en la resolución de sobrecarga a menos que
T
no sea un array.
2 Devuelve:unique_ptr<T>(new T(std::forward<Args>(args)...)).
template <class T> unique_ptr<T> make_unique(size_t n);
3 Observaciones: Esta función no participará en la resolución de sobrecarga a menos que
T
sea una matriz de límite desconocido.
4 Devuelve:unique_ptr<T>(new typename remove_extent<T>::type[n]()).
template <class T, class... Args> unspecified make_unique(Args&&...) = delete;
5 Observaciones: Esta función no participará en la resolución de sobrecarga a menos que
T
sea una matriz de enlace conocido.
Ahora, esto me parece ser tan claro como el barro, y creo que necesita más exposición. Pero, dejando de lado este comentario editorial, creo que he descifrado los significados de cada variante:
-
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
Su bog-standard
make_unique
para tipos que no son de array. Presumiblemente, la "observación" indica que alguna forma de aserción estática o truco SFINAE es evitar que la plantilla se instancie con éxito cuandoT
es un tipo de matriz.En un nivel alto, véalo como el puntero inteligente equivalente a
T* ptr = new T(args);
. -
template <class T> unique_ptr<T> make_unique(size_t n);
Una variante para tipos de matriz. Crea una matriz dinámicamente asignada de
n
×Ts
, y devuelve envuelto en ununique_ptr<T[]>
.En un nivel alto, véalo como el puntero inteligente equivalente a
T* ptr = new T[n];
. -
template <class T, class... Args> unspecified make_unique(Args&&...)
No permitido. "no especificado" probablemente sería
unique_ptr<T[N]>
.De lo contrario sería el puntero inteligente equivalente a algo como el
T[N]* ptr = new (keep_the_dimension_please) (the_dimension_is_constexpr) T[N];
no válido.
En primer lugar, ¿estoy en lo cierto? Y, si es así, ¿qué está pasando con la tercera función?
Si está ahí para rechazar a los programadores de intentar asignar dinámicamente una matriz mientras proporciona argumentos de constructor para cada elemento (al igual que
new int[5](args)
es imposible), entonces eso ya está cubierto por el hecho de que la primera función no puede ser instanciada para tipos de matriz, ¿no es así?Si está ahí para evitar la adición al lenguaje de una construcción como
T[N]* ptr = new T[N]
(dondeN
es algoconstexpr
) entonces, bueno, ¿por qué? ¿No sería completamente posible que existiera ununique_ptr<T[N]>
que envuelve un bloque dinámicamente asignado deN
×T
s? ¿Sería esto algo tan malo, en la medida en que el comité ha hecho todo lo posible para rechazar su creación utilizandomake_unique
?
¿Por qué make_unique<T[N]>
no está permitido?
2 answers
Citando la propuesta original:
T[N]
A partir de N3485,
unique_ptr
no proporciona una especialización parcial paraT[N]
. Sin embargo, los usuarios estarán fuertemente tentados a escribirmake_unique<T[N]>()
. Este es un escenario sin victoria. Devolverunique_ptr<T[N]>
seleccionaría el primario plantilla para objetos individuales, lo cual es extraño. Volviendounique_ptr<T[]>
sería una excepción a la regla de otra manera ironclad quemake_unique<something>()
devuelveunique_ptr<something>
. Por lo tanto, este propuesta haceT[N]
mal formado aquí, permitiendo que las implementaciones emitanstatic_assert
mensajes útiles.
El autor de la propuesta, Stephan T. Lavavej, ilustra esta situación en este video sobre Core C++ (cortesía de chris), a partir del minuto 1:01:10 (más o menos).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:16:56
Para mí, la tercera sobrecarga parece superflua, ya que no cambia el hecho de que las otras sobrecargas no coincidan con T[N]
y no parece ayudar a generar mejores mensajes de error. Consider the following implementation:
template< typename T, typename... Args >
typename enable_if< !is_array< T >::value, unique_ptr< T > >::type
make_unique( Args&&... args )
{
return unique_ptr< T >( new T( forward< Args >( args )... ) );
}
template< typename T >
typename enable_if< is_array< T >::value && extent< T >::value == 0, unique_ptr< T > >::type
make_unique( const size_t n )
{
using U = typename remove_extent< T >::type;
return unique_ptr< T >( new U[ n ]() );
}
Cuando intenta llamar a std::make_unique<int[1]>(1)
, el mensaje de error enumera ambos candidatos como desactivados por enable_if
. Si agrega la tercera sobrecarga eliminada, el mensaje de error enumera tres candidatos en su lugar. Además, dado que se especifica como =delete;
, no puede proporcionar una más mensaje de error significativo en el cuerpo de la tercera sobrecarga, por ejemplo, static_assert(sizeof(T)==0,"array of known bound not allowed for std::make_shared");
.
Aquí está el ejemplo en vivo en caso de que quieras jugar con él.
El hecho de que la tercera sobrecarga terminó en N3656 y N3797 es probablemente debido a la historia de cómo make_unique
se desarrolló con el tiempo, pero supongo que solo STL puede responder que:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-01 15:34:13