2010-01-30 34 views
6

Acabo de empezar a aprender sobre punteros en C++, y no estoy muy seguro de cuándo usar punteros, y cuándo usar objetos reales.Cuándo utilizar punteros en C++

Por ejemplo, en una de mis asignaciones tenemos que construir una clase gPolyline, donde cada punto está definido por un gVector. En este momento mis variables para la clase GPolyline se parece a esto:

private: 
vector<gVector3*> points; 

Si tuviera vector < gVector3> señala lugar, ¿qué diferencia habría? Además, ¿existe una regla general sobre cuándo usar punteros? ¡Gracias por adelantado!

+0

copias de memoria son el mayor impacto. Insignificante si estás hablando de tres entradas. – pestilence669

+2

@mloskot: si se hubiera molestado en verificar, habría visto que Alice solo ha hecho cuatro preguntas y aceptado las respuestas de las otras tres. Entonces, ella sabe claramente cómo funciona SO y, presumiblemente, está evaluando las respuestas para resolver lo que mejor responde a su pregunta. – ChrisF

+1

@Neil & @ChrisF - No estoy diciendo que haya ningún requisito. Tienes razón en esperar más de 1-2 horas. Saludos a Alice. – mloskot

Respuesta

2

La regla general es utilizar punteros cuando lo necesite y valores o referencias cuando pueda.

Si usa vector<gVector3>, los elementos de inserción harán copias de estos elementos y los elementos ya no se conectarán al elemento que insertó. Cuando almacena punteros, el vector solo se refiere al objeto que insertó.

Así que si quiere que varios vectores compartan los mismos elementos, para que los cambios en el elemento se reflejen en todos los vectores, necesita que los vectores contengan punteros. Si no necesita dicha funcionalidad, el almacenamiento de valores suele ser mejor, por ejemplo, le evita tener que preocuparse por cuándo eliminar todos estos objetos apuntados.

0

Puede usar punteros u objetos; es lo mismo al final del día.

Si tiene un puntero, tendrá que asignar espacio para el objeto real (luego señalarlo) de cualquier forma. Al final del día, si tiene un millón de objetos, independientemente de si está almacenando punteros o los propios objetos, tendrá espacio para un millón de objetos asignados en la memoria.

¿Cuándo utilizar punteros en su lugar? Si necesita pasar los objetos por su cuenta, modifique los elementos individuales después de que estén en la estructura de datos sin tener que recuperarlos todas las veces, o si está usando un administrador de memoria personalizado para administrar la asignación, la desasignación y la limpieza de los objetos.

Poner los objetos en la estructura STL es más fácil y simple. Requiere menos * y -> operadores que puede ser difícil de comprender. Ciertos objetos STL necesitarían tener los objetos en sí mismos presentes en lugar de punteros en su formato predeterminado (es decir, hashtables que necesitan cortar la entrada) y usted quiere manipular el objeto, no el puntero a él) pero siempre puede evitarlo funciones de anulación, etc.

En pocas palabras: utilice punteros cuando tenga sentido. Use objetos de otra manera.

+0

Todavía no es una buena idea usar punteros aquí. Sería mejor utilizar los iteradores de STL e iterar sobre las colecciones de esa manera. Si le preocupa el espacio objeto, es mejor utilizar alguna forma de 'shared_ptr'. Finalmente, el uso de punteros crudos rompe cada uno de los algoritmos estándar con la semántica de eliminación, como 'std :: remove',' std :: remove_if', 'std :: unique',' std :: replace', 'std :: replace_if', etc. –

1

En general, los punteros deben evitarse en C++. El propósito principal de los indicadores en la actualidad gira en torno al hecho de que los punteros pueden ser polimórficos, mientras que los objetos explícitos no lo son.

Cuando necesite polimorfismo hoy en día a pesar de que es mejor usar una clase puntero inteligente - como std::shared_ptr (si su compilador soporta C++ 0x extensiones), std::tr1::shared_ptr (si el compilador no admite C++ 0x, pero hace soporte TR1) o boost::shared_ptr.

+0

No sé qué quiere decir con "C++ moderno", pero en muchos proyectos grandes en los que he trabajado, he tenido que migrar el código de 'STL_Struct ' a 'STL_Struct ' :) A veces * necesitas * un puntero al objeto en lugar del objeto mismo por razones que aclaro en mi respuesta anterior ... Pero te concederé que generalmente no hay necesidad de punteros. –

+0

Por "C++ moderno" me refiero al estándar C++ 03, o C++ estandarizado ANSI/ISO. Varios compiladores antiguos no implementan completamente el estándar, y se necesitan punteros para revisar las incoherencias de los compiladores. –

+0

@Neil - Solucionado - También corrigió su nombre ... –

0

Normalmente utiliza objetos.
Es más fácil comer una manzana que una manzana en un palo (OK palo de 2 metros porque me gustan las manzanas dulces).

En este caso sólo lo hacen un vector <gVector3>

Si tuviera un vector < g3Vector * > esto implica que se están asignando dinámicamente nuevos objetos de g3Vector (utilizando el nuevo operador). Si es así, debes llamar a delete en estos punteros en algún momento y std :: Vector no está diseñado para hacer eso.

Pero cada regla es una excepción.

Si g3Vector es un objeto enorme que cuesta mucho copiar (difícil de leer lea su documentación), entonces puede ser más eficiente almacenarlo como un puntero.Pero en este caso usaría el boost :: ptr_vector <g3Vector> ya que esto administra automáticamente la vida útil del objeto.

+0

@Billy: lea sobre boost :: ptr_vector. –

+0

Lo siento, ese comentario fue pensado para otra publicación. –

1

En general, es una buena idea utilizar punteros cuando sea necesario, pero referencias u objetos alternativamente objetos (piense en valores) cuando sea posible.

Primero necesita saber si gVector3 cumple con los requisitos de los contenedores estándar, es decir, si el tipo gVector3 se puede copiar y asignar. Es útil si gVector3 también es construible por defecto (vea la nota de ACTUALIZACIÓN a continuación). Suponiendo lo hace, entonces usted tiene dos opciones, almacenar objetos de gVector3 directamente en std::vector

std::vector<gVector3> points; 
points.push_back(gVector(1, 2, 3)); // std::vector will make a copy of passed object 

o es propietario de creación (y también la destrucción) de gVector3 objetos manualmente.

std :: puntos vectoriales; points.push_back (nuevo gVector3 (1, 2, 3)); // ...

Cuando la matriz points ya no es necesaria, recuerde hablar de todos los elementos y llamar al operador delete.

Ahora, es su elección si puede manipular gVector3 como objetos (puede suponer que los considera valores u objetos de valor) porque (si, consulte la condición anterior) gracias a la disponibilidad del constructor de copias y al operador de asignación las siguientes operaciones son posibles:

gVector3 v1(1, 2, 3); 
gVector3 v2; 
v2 = v1; // assignment 
gVector3 v3(v2); // copy construction 

o si lo desea o necesita asignar objetos de gVector3 en de almacenamiento dinámico utilizando nuevo operador. Es decir, puede querer o necesitar administrar la vida de esos objetos por su cuenta.

Por cierto, es posible que también se pregunta When should I use references, and when should I use pointers?

ACTUALIZACIÓN: Aquí está la explicación de la nota sobre la constructibilidad por defecto. Gracias a Neil por señalar que inicialmente no estaba claro. Como Neil notó correctamente, no es requerido por el estándar C++, sin embargo, señalé esta característica porque es importante y útil. Si el tipo de T no es construible por defecto, lo que no es requerido por la norma de C++, entonces el usuario debe ser consciente de los problemas potenciales que trato de ilustrar a continuación:

#include <vector> 
struct T 
{ 
    int i; 
    T(int i) : i(i) {} 
}; 
int main() 
{ 
    // Request vector of 10 elements 
    std::vector<T> v(10); // Compilation error about missing T::T() function/ctor 
} 
+1

Tiene razón acerca de los requisitos que pueden copiarse y asignarse; está equivocado sobre el valor predeterminado que se puede construir. No existe tal requisito. –

+0

+1 para muy buen punto. He actualizado mi respuesta para que quede más claro. ¡Gracias! – mloskot

+0

Puede decir: std :: vector v (10, T (0)); También cometí este error: puede verlo en mi entrada de blog en el constructor predeterminado en http://punchlet.wordpress.com/2009/12/03/letter-the-third. –