luego
No quiero que se llame al constructor. Estoy usando la ubicación nueva.
Solo quiero asignar un bloque de T.
Mi enfoque estándar es:
T* data = malloc(sizeof(T) * num);
sin embargo, no sé si (data+i) está alineado en T. Además, no sé si esta es la forma correcta de “C++”.
¿Cómo debo asignar un bloque de T sin llamar a su constructor?
AnT apoya a Rusia
En primer lugar, no está asignando un “bloque de T*
“. Está asignando un “bloque de T
“.
En segundo lugar, si su T
tiene un constructor no trivial, luego, hasta que se construyan los elementos, su bloque no es realmente un “bloque de T”, sino un bloque de memoria sin procesar. No tiene sentido involucrar T
aquí en absoluto (excepto para calcular el tamaño). A void *
puntero es más apropiado con la memoria en bruto.
Para asignar la memoria puedes usar lo que prefieras
void *raw_data = malloc(num * sizeof(T));
o
void *raw_data = new unsigned char[num * sizeof(T)];
o
void *raw_data = ::operator new(num * sizeof(T));
o
std::allocator<T> a;
void *raw_data = a.allocate(num);
// or
// T *raw_data = a.allocate(num);
Más tarde, cuando realmente construyas los elementos (usando la ubicación nueva, como dijiste), finalmente obtendrás un puntero significativo de tipo T *
pero siempre que la memoria esté en bruto, usando T *
tiene poco sentido (aunque no es un error).
A menos que su T
tiene algunos requisitos de alineación exóticos, la memoria devuelta por las funciones de asignación anteriores se alineará correctamente.
Es posible que desee echar un vistazo a las utilidades de memoria proporcionadas por la biblioteca estándar de C++: std::allocator<>
con allocate
y construct
métodos y algoritmos como uninitialized_fill
etc. en su lugar o tratando de reinventar la rueda.
-
Creo que std::allocator es la forma “más C++” de hacerlo
– rmeador
4 de marzo de 2010 a las 22:33
-
¿Cómo se desasigna (llamando a los destructores) usando este método?
– André Puel
24 de agosto de 2011 a las 18:49
-
@André Puel: Haces todo al revés. En primer lugar, invoca manualmente los destructores uno por uno (hay una sintaxis para la invocación de destructores en C++). entonces tu solo
free
el recuerdo (si fueramalloc
ed), o utilice otra función apropiada de desasignación de memoria sin formato.– AnT apoya a Rusia
24 de agosto de 2011 a las 18:55
-
Mi punto es que suceden cosas malas si invocas eliminar[] en tu T*. Y si le das esta T* a otra persona y dices “Eres dueño de esta T*”, esta otra persona probablemente invocará la eliminación[]. Por favor incluya esta advertencia en su respuesta.
– André Puel
24 de agosto de 2011 a las 19:18
-
@André Puel: No. Ese es un tema totalmente diferente, que no tiene nada que ver con la pregunta formulada. Es como incluir una advertencia sobre los peligros de la división por cero en cada respuesta que incluso menciona el operador de división. La pregunta es sobre algunos detalles de la asignación personalizada, no sobre los conceptos básicos de la asignación personalizada.
– AnT apoya a Rusia
24 de agosto de 2011 a las 20:27
el regreso de malloc
está alineado para cualquier tipo, por lo que no es un problema.
Generalmente en C++, ::operator new
sería la forma preferida. También puede considerar usar un Allocator<T>
lo que brinda cierta flexibilidad adicional (como poder cambiar los asignadores fácilmente).
T* data = reinterpret_cast<T*>(operator new(sizeof(T) * num));
O simplemente usa std::vector<T>
y no se preocupe por estos detalles de memoria de bajo nivel;)
-
Creo que si T no es un tipo de POD, esto conduce a un comportamiento indefinido.
– GManNickG
4 de marzo de 2010 a las 22:10
-
vector invocará los constructores predeterminados para cada T.
– jmucchiello
4 de marzo de 2010 a las 22:40
¿Por qué no quieres llamar al constructor? Si es porque tu constructor está haciendo un trabajo que no siempre quieres hacer, podrías considerar mover ese trabajo a un método init() separado.
– RickNotFred
4 de marzo de 2010 a las 21:49
Por ejemplo, std::vector hace esto (asignar memoria sin construir todavía objetos).
– tío Bens
4 de marzo de 2010 a las 21:54