2010-08-05 9 views
12

Escribí el siguiente programa de ejemplo pero se bloquea con segfault. El problema parece ser con el uso de malloc y std::string s en la estructura.Cómo usar una cadena C++ en una estructura cuando malloc() - ing la misma estructura?

#include <iostream> 
#include <string> 
#include <cstdlib> 

struct example { 
std::string data; 
}; 

int main() { 
example *ex = (example *)malloc(sizeof(*ex)); 
ex->data = "hello world"; 
std::cout << ex->data << std::endl; 
} 

No puedo encontrar la manera de hacerlo funcionar. ¿Alguna idea si es posible usar malloc() y std::string s?

Gracias, Boda Cydo.

Respuesta

22

No se puede malloc una clase con un constructor no trivial en C++. Lo que obtienes de malloc es un bloque de raw memoria, que no contiene un objeto construido correctamente. Cualquier intento de usar esa memoria como un objeto "real" fallará.

En lugar de malloc objeto -ing, utilice new

example *ex = new example; 

Su código original puede ser obligado a trabajar con malloc así, mediante el uso de la siguiente secuencia de pasos: malloc memoria prima primero, construir el objeto en que la memoria prima segunda:

void *ex_raw = malloc(sizeof(example)); 
example *ex = new(ex_raw) example; 

La forma de new utilizado arriba se llama "colocación nueva". Sin embargo, no hay necesidad de todos estos trucos en su caso.

+0

Estoy usando malloc() porque new arroja excepciones en lugar de devuelve NULL. Simplemente no quería excepciones en esa parte del código. Ese código ocurre en una devolución de llamada de C y no quiero lanzar excepciones de C++ en una devolución de llamada de C. Entonces usé malloc. ¿Alguna idea sobre eso? – bodacydo

+1

@bodacydo: puede usar 'new (std :: nothrow) example' para hacer que' new' devuelva null-pointer en lugar de lanzar excepciones. Debe incluir el encabezado '' para usar la constante 'std :: nothrow'. – AnT

+1

@bodacydo: si realmente quiere 'new' devolver un puntero nulo en caso de error, use' new (nothrow) example'. Pero realmente deberías usar 'try' /' catch' para atrapar cualquier excepción lanzada. (La asignación 'std :: string', por ejemplo, también podría arrojar una excepción si no puede asignar memoria.) – jamesdlin

2

Al asignar memoria con malloc no se llama a ningún constructor. No mezcle la asignación C-style con los objetos C++. No juegan bien juntos. En su lugar, utilice el operador new para asignar objetos en código C++:

example *ex = new example; 

Este es el código más inteligente y va a llamar al constructor std::string::string() para inicializar la cadena, que se solucionará el error de segmentación que se está viendo. Y no se olvide de borrarlo cuando haya terminado para liberar la memoria y llamar a los destructores apropiadas:

delete ex; 
2

El problema es que malloc no llama al constructor de example. Como un string se suele representar como un puntero en la pila, se establece en cero y se desreferencia un puntero nulo. Necesitará usar new en su lugar.

3

Para una class o struct como su example, la respuesta correcta es utilizar new no malloc() asignar una instancia. Solo operator new sabe cómo llamar a los constructores para el struct y sus miembros. Su problema es causado por el miembro de cadena que no se haya construido nunca.

Sin embargo, hay casos raros donde es importante que un parche de memoria en particular actúe como si tuviera una instancia de una clase. Si realmente tiene un caso así, existe una variación de operator new que permite especificar la ubicación del objeto. Esto se llama "placement new" y debe usarse con sumo cuidado.

void *rawex = malloc(sizeof(example)); // allocate space 
example ex = new(rawex) example();  // construct an example in it 
ex->data = "hello world";    // use the data field, not no crash 
// time passes 
ex->~example();       // call the destructor 
free(rawex);       // free the allocation 

Al utilizar la ubicación nueva, está obligado a proporcionar un área de memoria del tamaño y la alineación correctos. No proporcionar el tamaño o la alineación correctos hará que las cosas misteriosas salgan mal. La alineación incorrecta suele ser más rápida para causar un problema, pero también puede ser misteriosa.

Además, con una ubicación nueva, se está responsabilizando de llamar al destructor a mano, y dependiendo del origen del bloque de memoria, liberándolo a su propietario.

Con todo, a menos que ya sepa que necesita una ubicación nueva, es casi seguro que no la necesita. Tiene usos legítimos, pero hay rincones oscuros de marcos y no ocurrencias cotidianas.

+0

Nunca escuché nada de esto. ¡Gracias! – bodacydo

0

no se debe utilizar

ejemplo * ex = (ejemplo *) malloc (sizeof (* ex));

porque lo que sizeof (* ex) return es igual al tamaño de largo o tamaño de int, que se debe a que el entorno de compilación es diferente. se puede utilizar código de la siguiente manera:

ejemplo * ex = (ejemplo * ) malloc (sizeof (ejemplo));

+0

Cualquiera de los métodos para generar el tamaño funcionará. –

+0

Alguien votará negativamente esto si no tiene cuidado (ya que es incorrecto). –

Cuestiones relacionadas