no se me permite usar Vectores específicamente para esta tarea escolar. La mayoría de las respuestas que he encontrado simplemente dicen "deberías usar vectores" como el comentario más votado. Si bien aprecio y entiendo esto, simplemente estoy restringido de usarlos para esta tarea.

Es una asignación de C ++ con administración de memoria dinámica de la siguiente manera:

// property in header declaration
int numAnimals;
int capacity;
Animal** animals; 
void addAnimal(Animal *newAnimal);

// class implementation
capacity = 10;
numAnimals = 0;

animals = new Animal*[capacity];

void SampleClass::addAnimal(Animal *newAnimal)
{
  for (int i = 0; i < capacity; i++){
       if(animals[i]){
          // animal object already exists in array, move on
          i++;
       }else{
          animals[i] = newAnimal;
          numAnimals++;
          break;
       }
   }
}

Animals es un puntero a un puntero, en este caso un puntero a una matriz de punteros al tipo de objeto Animal que aún no se ha creado.

Con la función 'addAnimal', lo que intento hacer es agregar un objeto animal a la matriz haciendo un bucle a través de la matriz de punteros, y si ya existe un objeto animal, iterar al siguiente índice. Si no hay un animal, inserte ese animal en la matriz.

Recibo una excepción "violación de acceso de lectura" cuando intento acceder a una función miembro de un objeto animal en la matriz.

Mi sospecha es porque: if (animals [i]) probablemente no está haciendo lo que creo que está haciendo, ejecutándolo a través del depurador nunca presioné la parte 'else', por lo que la matriz todavía está llena de punteros que no se establecen en ningún objeto cuando se completa el método . Por lo tanto, cuando intento acceder a una función miembro, se trata de un objeto que no existe.

Entonces, si mis sospechas son correctas, ¿cuál es la mejor manera de insertar un nuevo objeto en una matriz de punteros de esta manera? Deben ser punteros; de lo contrario, crea automáticamente la matriz llena de objetos poblados, que no es lo que quiero.

No publiqué todo el código porque quería mantener mi problema breve, disculpas, soy nuevo en C ++ y stackoverflow en general. Sí, sé eliminar [] para borrar la memoria después.

Cualquier ayuda es apreciada, gracias!

3
Matthew S 20 oct. 2017 a las 13:35

3 respuestas

La mejor respuesta

Dado que en numAnimals mantiene el recuento del número actual de punteros de animales en la matriz, no necesita el bucle for para encontrar el primer espacio disponible para agregar un nuevo puntero de animales (tenga en cuenta también que, suponiendo que desea utilizar un bucle for como se muestra en su código, debe prestar atención para inicializar correctamente todos los punteros iniciales en la matriz a nullptr).

Solo puedes usar:

// Inside SampleClass::addAnimal(Animal *newAnimal):

animals[numAnimals] = newAnimal;
numAnimals++;

Tenga en cuenta que debe prestar atención a no desbordar su capacidad de matriz cuando inserte un nuevo animal.
Entonces, antes de insertar un nuevo animal, debe verificar que haya suficiente espacio en la matriz, por ejemplo:

// Before inserting:
if (numAnimals == capacity) 
{
    // You ran out of capacity.
    //
    // 1. Allocate a new array with bigger capacity (e.g. 2X)
    // 2. Copy the content from the current array to the new one
    // 3. delete current array
}

Como nota al margen:

Sí, sé que delete[] para borrar la memoria después

Tenga en cuenta que si llama a delete[] en la matriz de punteros animals, libera esta matriz de punteros, pero no los objetos Animal apuntados.

5
Mr.C64 20 oct. 2017 a las 10:53

La cuestión es "Usar un vector", a pesar de que su maestro le diga lo contrario, es la forma correcta de hacerlo. Sin embargo, si se supone que debe administrar la matriz dinámica manualmente, lo mejor que puede hacer es encapsular todas esas cosas sucias de memoria dentro de un class y escribir su propio reemplazo para std::vector. Es decir, para evitar que las asignaciones dinámicas se extiendan por todo el código (especialmente en lugares que se supone que deben tratar con Animal sy no deberían preocuparse por asignar manualmente la memoria y similares), debe escribir un class que haga eso (y nada más) y proporciona una interfaz más agradable. Solo puedo resumir la idea aquí:

template <typename T> 
class my_vector {
    private:
        T* data;
        size_t size;
        size_t capacity;
    public:
        void push_back(const T& t);
        size_t size();
        T& operator[](size_t index);
        void resize(size_t size);
        //... etc...
};
2
idclev 463035818 20 oct. 2017 a las 11:14
int capacity = 10;
Animal** animals = new Animal*[capacity];

Esto asigna diez punteros, excepto que no inicializa, lo que significa que tiene esencialmente datos basura.

if (animals[i])

Prueba uno de esos punteros contra nullptr, pero como lo hiciste sin inicialización, no es muy probable que sea nullptr.

Debe agregar un pase de bucle que anule los datos, justo después de asignarlo:

for(int i=0; i<capacity; ++i)
    animals[i] = nullptr;

También hay un error:

if (animals[i]) {
    // animal object already exists in array, move on
    i++; // <- here

Esto está mal, sigue adelante dos veces for (int i = 0; i < capacity; i ++ )

4
sp2danny 20 oct. 2017 a las 10:53