Colocación nuevo en std:: almacenamiento alineado?
Supongamos que tengo un parámetro de plantilla de tipo T.
Y supongamos que tengo un std::aligned_storage
de la siguiente manera:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
Quiero colocar una nueva T en el storage
.
¿Cuál es el valor/tipo de puntero compatible con el estándar para pasar al nuevo operador de colocación, y cómo obtengo eso de storage
?
new (& ???) T(a,b,c);
Por ejemplo:
new (&storage) T(a,b,c);
new (static_cast<void*>(&storage)) T(a,b,c);
new (reinterpret_cast<T*>(&storage)) T(a,b,c);
new (static_cast<T*>(static_cast<void*>(&storage));
¿Cuáles de los anteriores (si los hay) son compatibles, y si ninguno, cuál es la mejor manera?
2 answers
La forma más paranoica es{[19]]}
::new ((void *)::std::addressof(storage)) T(a, b, c);
Explicación:
-
::std::addressof
protege contra la sobrecarga de unaryoperator&
enstorage
, que está técnicamente permitido por el estándar. (Aunque ninguna implementación sensata lo haría.) El::std
protege contra cualquier espacio de nombres (o clases) no de nivel superior llamadostd
que pueda estar en el ámbito. -
(void *)
(que en este caso es el equivalente de unstatic_cast
) asegura que llame a la colocaciónoperator new
tomando unvoid *
en lugar de otra cosa comodecltype(storage) *
. -
::new
omite cualquier ubicación específica de la claseoperator new
, asegurando que la llamada vaya a la global.
Juntos, esto garantiza que la llamada va a la ubicación de la biblioteca operator new
tomando un void *
, y que el T
se construye en donde está storage
.
En la mayoría de los programas cuerdos, sin embargo,
new (&storage) T(a,b,c);
Debería ser suficiente.
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
2018-09-04 21:28:55
La función de asignación de colocación se describe de la siguiente manera (C++14 n4140 18.6.1.3):
void* operator new(std::size_t size, void* ptr) noexcept;
Regresos:
ptr
.Observaciones: Intencionalmente no realiza ninguna otra acción.
20.10.7.6 la tabla 57 describe aligned_storage<Len, Align>
así:
El miembro typedef
type
será un tipo de vaina adecuado para su uso como almacenamiento no iniciado para cualquier objeto cuyo tamaño es como máximo Len y cuya la alineación es un divisor de Alinear.
Esto implica que en su caso, &storage
está adecuadamente alineado para sostener un objeto de tipo T
. Por lo tanto, en circunstancias normales1, las 4 formas que has enumerado de calling placement new
son válidas y equivalentes. Usaría el primero (new (&storage)
) para brevedad.
1 T. C. señaló correctamente en los comentarios que es técnicamente posible para su programa declarar una sobrecarga de la función de asignación tomando un typename std::aligned_storage<sizeof(T), alignof(T)>::type*
, que luego se seleccionaría por resolución de sobrecarga en lugar de la versión 'placement new' provista por la biblioteca.
Diría que esto es poco probable en al menos el 99,999% de los casos, pero si necesita protegerse contra eso también, use uno de los moldes para void*
. El static_cast<void*>(&storage)
directo es suficiente.
Además, si estás paranoico a este nivel, probablemente deberías usar ::new
en lugar de solo new
para omitir cualquier función de asignación específica de clase.
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
2015-01-28 12:40:22