entre diferencias c++ c++14

diferencias - c++17



ColocaciĆ³n nueva en std:: alineado_storage? (2)

La forma más paranoica es

::new ((void *)::std::addressof(storage)) T(a, b, c);

Explicación:

  • ::std::addressof guardias contra el operator& unario sobrecargado operator& en storage , técnicamente permitido por la norma. (Aunque ninguna implementación sensata lo haría). ::std protege contra cualquier espacio de nombres (o clases) que no sea de nivel superior llamado std que pueda estar dentro del alcance.
  • (void *) (que en este caso es el equivalente a un static_cast ) garantiza que usted llame al operator new ubicación operator new tome un void * lugar de otra cosa como decltype(storage) * .
  • ::new omite cualquier operator new colocación de clase específica, asegurando que la llamada se dirija a la global.

Juntos, esto garantiza que la llamada se dirija al operator new colocación de la biblioteca operator new tomando un void * , y que la T se construya en el lugar donde se encuentra el storage .

En la mayoría de los programas sanos, sin embargo,

new (&storage) T(a,b,c);

debería ser suficiente

Supongamos que tengo un tipo de plantilla de parámetro T.

Y supongamos que tengo un std::aligned_storage como sigue:

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 que cumple con la norma para pasar al nuevo operador de colocación, y cómo se obtiene eso del 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ál de los anteriores (si corresponde) cumple, y si ninguno, cuál es la mejor manera?


La función de asignación de ubicación se describe a continuación (C ++ 14 n4140 18.6.1.3):

void* operator new(std::size_t size, void* ptr) noexcept;

Devoluciones: ptr .

Observaciones: Intencionalmente no realiza ninguna otra acción.

20.10.7.6 la tabla 57 describe el aligned_storage<Len, Align> así:

El type typedef miembro será un tipo POD adecuado para usar como almacenamiento no inicializado para cualquier objeto cuyo tamaño sea a lo sumo Len y cuya alineación sea un divisor de Alinear.

Esto implica que, en su caso, &storage se alinea adecuadamente para contener un objeto de tipo T Por lo tanto, en circunstancias normales 1 , las 4 formas en que ha enumerado la ubicación de la llamada new son válidas y equivalentes. Yo usaría el primero ( new (&storage) ) por brevedad.

1 TC señaló correctamente en los comentarios que es técnicamente posible que su programa declare una sobrecarga de la función de asignación tomando un typename std::aligned_storage<sizeof(T), alignof(T)>::type* , que luego se seleccionará por resolución de sobrecarga en lugar de la versión ''nueva ubicación'' provista por la biblioteca.

Yo diría que esto es poco probable en al menos el 99,999% de los casos, pero si también necesita protegerse contra eso, use uno de los modelos para void* . El static_cast<void*>(&storage) directo static_cast<void*>(&storage) es suficiente.

Además, si está paranoico a este nivel, probablemente debería usar ::new lugar de simplemente new para omitir cualquier función de asignación específica de la clase.