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?

 25
Author: Andrew Tomazos, 2015-01-28

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 unary operator& en storage, 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 llamado std que pueda estar en el ámbito.
  • (void *) (que en este caso es el equivalente de un static_cast) asegura que llame a la colocación operator new tomando un void * en lugar de otra cosa como decltype(storage) *.
  • ::new omite cualquier ubicación específica de la clase operator 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.

 39
Author: T.C.,
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.

 4
Author: Angew,
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