2010-05-18 49 views

Respuesta

20

Básicamente, un remanente de C.

¿Cuál es su uso?

En C, que eran y son utilizados ampliamente, pero en C++, creo que son muy rara vez, o nunca, es necesario, ya que tenemos el polimorfismo, plantillas, etc., que proporcionan una forma mucho más limpio y más seguro para resolver el mismos problemas donde en C uno usaría punteros vacíos.

¿Puedo hacer que apunten a una variable de cualquier tipo?

Sí. Sin embargo, como han señalado otros, no puede usar un puntero de vacío directamente; primero tiene que convertirlo en un puntero a un tipo de datos concretos.

+0

Eso hace las cosas ... interesantes. Gracias por su respuesta rápida :) Sé que es probablemente una mala práctica, pero podría ser muy útil para mí en algunos casos! –

+9

Si está escribiendo en C++ (y no en C), utilizar 'void *' es casi siempre lo incorrecto. ¿Por qué no mejorar sus habilidades en C++ buscando las formas * correctas * de manejar estos casos? –

+0

Aunque no estoy en desacuerdo con que se debe evitar el vacío *, ya que normalmente hay mejores formas de hacer las cosas en C++, todavía hay algunos casos inusuales en los que son valiosos o necesarios. Un ejemplo de este último es determinar si un par de referencias son para el mismo objeto, cuando las referencias son a diferentes clases padre de un objeto heredado de múltiples. –

7

Sí, esta es una construcción C (no específica de C++) que le permite declarar una variable de puntero que apunta a cualquier tipo. En realidad, no se puede hacer mucho con un puntero como este, excepto devolverlo al objeto real al que realmente apunta. En C++ moderno, void * ha pasado prácticamente de moda, cediendo en muchos casos al código genérico basado en plantillas.

4

De cplusplus.com:

El tipo de puntero nulo es un especial tipo de puntero. En C++, void representa la ausencia de tipo, por lo que punteros vacíos son punteros que apuntan a un valor que no tiene ningún tipo (y por lo tanto también una longitud indeterminada y propiedades de desreferencia indeterminadas).

Esto permite que los punteros vacíos apunten a cualquier tipo de datos, desde un valor entero o un flotador a una cadena de caracteres. Pero en cambio tienen una gran limitación: los datos apuntados por ellos no puede dejar de hacer referencia directa (que es lógico, ya que contamos con ningún tipo de eliminar la referencia a), y por esa razón que siempre tendrán que emitir el dirección en el puntero de vacío a algún otro tipo de puntero que apunta a un tipo de datos concreto antes de desreferenciarlo.

6

Uno de los pocos usos que existen para los punteros vacíos en C++ es su uso en la sobrecarga de los operadores new. Todos los operadores new devuelven el tipo void* por definición. Aparte de eso, lo que otros han dicho es verdad.

1

Un puntero nulo puede apuntar a cualquier cosa, siempre y cuando su memoria :-)

Los estados C estándar que puede convertir cualquier puntero a un vacío triple, entonces echarlo hacia atrás sin perder nada.

0

vacío ptr es básicamente una caja vacía. Llénalo con lo que quieras pero asegúrate de etiquetarlo (tupecasting)

+2

Creo que te refieres a "encasillamiento", aunque "tuplecasting" suena como el nombre de un nuevo paradigma emocionante a la espera de ser descubierto. – AShelly

+0

Creo que 'tupecasting' es un error tipográfico para' upcasting'. Habiendo dicho eso, se lanza al vacío, a un tipo específico. –

0

Los uso en mis listas dinámicas para contener más tipos de objetos (todos son punteros).
typedef void* Object; Luego, cuando se declara una variable de objeto que puede almacenar cualquier puntero en ella. Es más o menos útil según las necesidades.
Me resulta muy útil cuando tienes que guardar cualquier puntero en alguna parte y no puedes derivar todas tus clases de una sola. Aparte de eso, como otros dijeron que es mejor usar plantillas, polimorfismo, etc.

+3

Algo como boost :: any o boost :: variant puede ser mejor para la mayoría de los usos de void *. –

1

Un puntero a void es el concepto más cercano a un puntero de lenguaje ensamblador. Es un puntero genérico que reserva espacio para una dirección o ubicación de algo (función o dato). Como otros han declarado, debe ser lanzado antes de que pueda ser desreferenciado.

El puntero void es una herramienta popular para la representación de objetos conceptos Orient en el lenguaje C. Un problema con el puntero de vacío es que el contenido puede no coincidir con la percepción del receptor. Si el que llama establece el puntero para apuntar a un cuadrado, pero la función de recepción espera un puntero a un gato, las cosas indefinidas y extrañas sucederán con el puntero emitido.

4

Tipo ocultar. Todavía tiene sus usos válidos en C++ moderno. Explore el código fuente en boost y encontrará algunos. En general, el uso de un vacío * está enterrado a gran profundidad dentro de las entrañas de una construcción más compleja que garantiza el tipo de seguridad de la interfaz mientras se realiza magia negra y maligna.

3

Lo hicieron una vez en C realizan el trabajo de ser el puntero a cualquier cosa, un puntero que pasó a las bibliotecas y le devolvieron como datos de usuario. Un vacío * no sirve de nada sin que el programador conozca su contexto de alguna manera, ya que no sabe qué hay al otro lado, no puede hacer nada con los datos. Excepto pasar el puntero a algún otro código que sí lo sepa.

Lo que no entiendo es por qué la gente no sólo tiene que utilizar tipos no definidos, es decir puntero opaco. Escriba seguridad, datos de usuario.

En la moderna ++ C, el vacío puntero-a-es casi totalmente reemplazado por el polimorfismo y código genérico generada plantilla. Sin embargo, es posible que aún tenga que usarlos para interactuar con el código C nativo. Para utilizar un vacío * de forma segura, en cualquier contexto dado, solo eche un tipo a un vacío *. De esa forma, sabes con certeza a qué apunta. Si necesita más tipos, se podría hacer una rápida
struct safevoidptr { base* ptr };
o
struct safevoidptr { void* ptr; int type; };
Creo que dynamic_cast también podría ser capaz de convertir void * a tipos polimórficos, aunque nunca he utilizado moldeado dinámico, así que no tome mi palabra para ello.

0

cosas que podría hacer en C con vacío, pero no puede en C++:

void * 's se convierten automáticamente a otros tipos de puntero. (Usted sabe es un void * - no ganas la seguridad de tipos de forzar una conversión explícita)

Struct* p = malloc(sizeof(Struct)); 
// vs C++ 
Struct* p = (Struct*)malloc(sizeof(Struct)); 
// Some will argue that that cast style is deprecated too, and c++ programmers 
// need to actually do this: 
Struct* p = reinterpret_cast<Struct*>malloc(sizeof(Struct)); 
// See what C++ did there? By making you write Struct a 3rd time, you can now be sure 
// you know what you are doing! 

void * 's también hizo el recuento de indirección en C, lo que permite una mayor seguridad al pasar punteros a funciones que toman un puntero a un puntero.

void funcInitializingOutPtr(void** ppOut) 
{ 
    *ppOut = malloc(x); 
} 

int* out = NULL; 
funcInitializingPtr(out); // C would signal this as an error 
funcInitializingPtr(&out); // correct 
// vs C++ 
funcInitializingPtr((void**)&out); // so much safer needing that exlicit cast. 
funcInitializingPtr((void**)out); // oops. thanks C++ for hiding the common error 
1

Dado que ya hay tantas buenas respuestas, solo proporcionaría una de las más comunes que vi: especialización de plantillas. Si no recuerdo mal, el libro de Stroustrup tiene un ejemplo de esto: vector especializado como vector, luego tener vector para derivar (privadamente) del vector. De esta forma, el vector solo contendrá códigos sencillos y fácilmente integrados (es decir, llame a funciones relevantes del vector). Esto reducirá el número de duplicaciones cuando el vector se compila en un programa que lo usa con muchos tipos diferentes de punteros.

0

I belive void * es la ubicación de la memoria donde puede escribir/Almacenar cualquier cosa. Algún Analista de Idiomas no estará de acuerdo conmigo en esto. pero lo he usado con éxito en muchos de mis proyectos.

El único problema que veo es de tipo de seguridad

Cuestiones relacionadas