c++ - usar - Valor de retorno de la colocación nueva
retornar valor en c (2)
Considere el siguiente código de C ++ 14:
#include <cassert>
#include <new>
#include <type_traits>
struct NonStandardLayout
{
// ...
};
int main()
{
using T = NonStandardLayout;
std::aligned_storage_t< sizeof(T), alignof(T) > storage;
T *const valid_ptr = new(static_cast<void *>(&storage)) T;
T *const maybe_ptr = reinterpret_cast<T *>(&storage);
assert(maybe_ptr == valid_ptr); // ???
valid_ptr->T::~T();
return 0;
}
¿Está garantizado por el estándar que la afirmación en el ejemplo nunca fallará, para cualquier tipo T?
Discusión
Mirando el último estándar ( http://eel.is/c++draft/ ), no puedo ver ninguna referencia a este escenario en particular, pero he encontrado los siguientes párrafos que posiblemente apuntan a la respuesta ''sí''.
¿Es correcto de mi parte pensar que [expr.new/15] y [new.delete.placement / 2] juntos valid_ptr
que el valor de valid_ptr
será igual a la dirección de storage
, siempre?
Si es así, ¿es cierto que reinterpret_cast
generará un puntero a un objeto completamente construido? Porque, [expr.reinterpret.cast / 7], [expr.static.cast / 13] y [basic.compound / 4] juntos parecen indicar que debería ser el caso.
De mis observaciones, las implementaciones de la biblioteca del asignador predeterminado parecen ser similares a esto y sin preocuparse. ¿Es realmente seguro lanzar así?
¿Cómo podemos estar seguros de que los dos punteros serán los mismos, o podemos?
18.6.1.3 Formas de colocación [new.delete.placement]
void * operator new (std :: size_t size, void * ptr) noexcept;
Devoluciones: ptr.
Se especifica de forma inequívoca que el new
operador de colocación devuelve cualquier puntero que se le pase. "Devoluciones: ptr". No puedo ser más claro que eso.
Eso, más o menos, sella el trato para mí en la medida en que va "el valor de retorno de la colocación nueva": la colocación new
no hace nada al puntero que coloca, y siempre devuelve el mismo puntero.
Todo lo demás en su pregunta se relaciona con cualquier otro cambio que pueda ocurrir como resultado de los otros lanzamientos; pero está preguntando específicamente sobre el valor de retorno de la ubicación new
, por lo que entiendo que está aceptando que todas las demás conversiones son solo conversiones de tipo y no tienen ningún efecto en el puntero real, y que solo estaba preguntando sobre la ubicación nueva - pero también sería posible pasar por los otros modelos y hacer una determinación similar.
Me sorprende que nadie haya mencionado este contraejemplo barato todavía:
struct foo {
static foo f;
// might seem dubious but doesn''t violate anything
void* operator new(size_t, void* p) {return &f;}
};
Sin embargo, a menos que se llame a una versión de ubicación específica de la clase, su afirmación debe ser válida. Ambas expresiones tienen que representar la misma dirección que se explica en la otra respuesta (el punto principal es que el operator new
no asignador estándar simplemente devuelve el argumento del puntero y la nueva expresión que no hace nada sofisticado), y ninguna de estas es un puntero pasado el final de algún objeto, por [expr.eq] / 2, se compara igual.