2009-06-19 17 views
6

Esta es una clase de C++ que he creado con n punteros.haciendo numerosos punteros NULL al mismo tiempo

class SomeClass 
{ 
private: 
     int* ptr1; 
     int* ptr2; 
     ... 
     int* ptrn; 

private: 
     // constructors, destructors, and methods 
}; 

Durante la fase de inicialización, quiero hacer todos los punteros apuntan a NULL (o hacer punteros apuntan a NULL de forma predeterminada cuando se declaran) en lugar de hacerlo:

void SomeClass::MakePtrNull() 
{ 
     ptr1 = NULL; 
     ptr2 = NULL; 
     ... 
     ptrn = NULL; 
} 

¿Hay cualquier método fácil de lograr este objetivo? Me pregunto si hay alguna forma de evitar escribir n líneas de ptr = NULL; en mi función. Gracias por adelantado.

AÑADIDO basado en las respuestas que he recibido hasta ahora: Por desgracia, los punteros tienen que estar separados, ya que se utilizan para diferentes propósitos. Hice los nombres de los punteros como tal solo para hacer un punto de lo que estoy tratando de hacer, pero cada puntero tiene un propósito completamente diferente. Supongo que tendré que hacer que apunten a NULL como ya lo hice. Gracias por tus respuestas.

+0

Tenga en cuenta que si la clase no tiene un constructor declarado por el usuario, SomeClass() tendrá todos los punteros a cero. Eso significa que puedes hacer * this = SomeClass(); y haría todos los indicadores a null-punteros. –

+0

@litb, en mis pruebas, solo las instancias estáticas de SomeClass tienen todos los punteros puestos a cero; las instancias automáticas y de montón obtienen lo que estaba en la pila o en el montón. –

+0

asumiendo que no hay un constructor declarado por el usuario, entonces SomeClass() se inicializa en oposición a "a" en {SomeClass a; }. SomeClass() value-initializes, recursivamente, todos sus miembros. Esto hará que los punteros sean nulos. Si define una variable automática y no tiene un constructor declarado por el usuario, no se inicializa. Tendría que hacer, por ejemplo, {SomeClass a = SomeClass(); } –

Respuesta

6

¿Por qué no utiliza una matriz o un vector en lugar de crear n punteros con nombre individual? Entonces puede hacer la anulación en un ciclo corto para.

5

Usted puede hacer esto:

void SomeClass::MakePtrNull() 
{ 
     ptr1 = ptr2 = ptr3 = ... = ptrn = NULL; 
} 
3

En primer lugar, la técnica que no trabajo:

Calling memset para establecer el objeto entero a cero no es suficiente. Primero, causará muchos problemas si su función tiene una o más funciones virtuales, y segundo, no se garantiza que un puntero nulo esté representado por un patrón de bits de todos los ceros.

Lo que probablemente haría en su caso es almacenar los punteros en una matriz o un vector. Luego puede usar la función std::fill para establecerlos todos en NULL. (O puede usar un ciclo si lo prefiere)

Por supuesto, si necesita hacer esto con la suficiente frecuencia, puede valer la pena escribir una clase contenedora que se comporte como el puntero, pero que lo establece en NULO en su valor predeterminado constructor.

O podría usar boost :: optional que funciona esencialmente así. (Aunque no es específica para los punteros)

+1

Usted dice que no se garantiza que un puntero nulo sea presentado por un patrón de bits de todos los ceros, ¿eso implica que una verificación if como esta: if (ptr1) no es una forma segura de determinar que un puntero no es nulo ? –

+0

Sí, sírvanse explicar en qué escenario 0x0 no es una dirección válida "sin memoria asignada aquí". Además, si la estructura/clase (así como sus clases principales) no tiene métodos virtuales, entonces su tamaño será exactamente la suma de los tamaños de sus miembros. –

+1

@average. Eso es seguro. Un ptr nulo debe evaluar falso, pero la implementación puede representarlo en la memoria como quiera. En la práctica, casi todo el mundo usa 0, porque un ptr NULL también debe convertir al entero como 0 y, por lo general, es más fácil y eficiente no cambiar el patrón de bits. @Shane: la estructura necesita ser POD para lo que dices que está garantizado por el estándar. Hay otras cosas además de los métodos virtuales que pueden hacer que una estructura no sea POD, y tener cualquier clase base es una de ellas. –

2

por qué no utilizar un constructor por defecto:

SomeClass::SomeClass() : ptr1(NULL), ptr2(NULL), ... 
{ 

} 

También puede hacer:

ptr1 = ptr2 = ptr3 = NULL; 
0

usar un vector para esto (porque por los sonidos de no será necesario que edites la lista en el futuro, y necesitas acceso aleatorio). Puede hacerlo de esta manera:

class PointerList 
{ 
private: 
    typedef std::vector<int*> IntPtrVector; 
    IntPtrVector m_ptrVec; 

public: 
    PointerList() 
    { 
     m_ptrVec.reserve(5); 
     for (int i = 0; i < 5; i++) 
      m_ptrVec.push_back(NULL); 
    } 

    int* getPointer(int index) 
    { 
     return m_ptrVec[index]; 
    } 

    void setPointer(int index, int* ptr) 
    { 
     assert(index <= 4); 
     m_ptrVec[index] = ptr; 
    } 
}; 

EDITAR

aunque para ser honesto, esto huele a ghettoness. ¿Estás seguro de que tu problema requiere esta solución? Si elabora más sobre su problema específico, quizás en otra pregunta, estoy seguro de que puede obtener una mejor respuesta sobre cómo lograr lo que desea de forma más elegante, en lugar de crear un segundo problema.

+0

El objetivo de la pregunta es si puedo tomar una salida perezosa que funcione. Gracias por su tiempo en las sugerencias sin embargo. – stanigator

11

En lugar de int *, cree una clase inteligente puntero similar a la que funciona exactamente igual que un int *, pero por defecto constructos con NULL:

template <typename T> 
class MyPointer { 
    T *p; 

public: 
    MyPointer() : p(NULL) { } 
    MyPointer(T *o) : p(o) { } 
    operator T*() const { return p; } 
    // ...and the rest of the traditional smart-pointer operators 
}; 

A continuación, utilizarlo en su clase:

class SomeClass 
{ 
private: 
     MyPointer<int> ptr1; 
     MyPointer<int> ptr2; 
     ... 
     MyPointer<int> ptrn; 

private: 
     // constructors, destructors, and methods 
}; 

Cada variable del tipo MyPointer<int> se inicializará automáticamente correctamente en los constructores de SomeClass, sin la necesidad de ningún tipeo adicional. Si no olvidó o implementó incorrectamente alguno de los métodos de MyPointer, actuará exactamente como un puntero normal y tendrá exactamente el mismo tamaño y rendimiento.

+2

+1 para usar el sistema de tipo para expresar exactamente la intención de programación. –

+0

Otra ventaja es que usted y los mantenedores de código no necesitarán inicializar los punteros en cada constructor, o recuerden actualizar las listas de inicializadores si cambia el número o nombre de los miembros de MyPointer. –

+0

También - 0 overhead de tiempo de ejecución – Eclipse

1

Puede poner los punteros en una estructura y luego memset() la estructura cuando sea necesario. Los punteros aún están separados, pero tiene los medios para seleccionarlos como una sola unidad sin afectar al resto de la clase. Por ejemplo:

struct MyPointers 
{ 
    int* ptr1; 
    int* ptr2; 
    ... 
    int* ptrn; 
}; 

class SomeClass 
{ 
private: 
    MyPointers ptrs; 
    ... 
}; 

void SomeClass::MakePtrNull() 
{ 
    memset(&ptrs, 0, sizeof(ptrs)); 
} 
+1

memset no funciona así. ver la respuesta de jalf –

3

te recomiendo hacer lo siguiente, si usted tiene que mantener los punteros separado (probablemente la necesidad más urgente sería si los punteros pueden tener diferentes tipos)

class SomeClass { 
    struct Pointers { 
     int* ptr1; 
     int* ptr2; 
     float* ptrn; 
    } ptrs; 

public: 
    void MakePtrNull(); 
}; 

void SomeClass::MakePtrNull() 
{ 
    // clears all pointers at once 
    ptrs = Pointers(); 
} 

Este funciona, porque la inicialización del valor para las clases que no tienen un constructor declarado por el usuario va a valorar la inicialización de todos sus miembros. La inicialización del valor de un puntero creará un puntero nulo.

+0

Esa es una gran técnica. +1 –

Cuestiones relacionadas