Нарушение доступа к динамическому массиву в C ++ - PullRequest
0 голосов
/ 22 сентября 2009

**** Извините за путаницу в отношении numCars в оригинальном сообщении. Я изменил код, чтобы он соответствовал оригинальному ******

Следующая академическая программа является упрощенной версией исходной проблемы, но она сосредоточена на проблеме, которую мне еще предстоит решить. Есть 2 класса и основной метод для этой проблемы, и 2 класса состоят из класса Dealer и класса Car. Класс Dealer имеет частный указатель Car *, который инициализируется динамическим массивом в конструкторе Dealer. Ошибка возникает в основном методе, когда вызывается метод addCar Дилера. В основном методе я намеренно передаю переменную Dealer в метод addCar (Dealer & d), чтобы имитировать структуру исходного приложения. Затем метод addCar вызывает метод дилера addCar (const Car & car), где нарушение прав доступа происходит, когда я выполняю cars [numCars ++] = car; Можете ли вы объяснить, почему автомобили [numCars ++] = машина приводят к нарушению прав доступа

/**********************************Dealer.h**************************/
#include <cstdlib>
#include "Car.h"

using namespace std;

class Dealer
{
    public:
        Dealer(int maxCars = DEFAULT_MAX_CARS)

: numCars (0) {cars = new Car [maxCars];}

        ~Dealer(){delete [] cars;}

        int getTotalCars() const { return numCars;}

        void addCar(const Car& car)
        {       
             cars[numCars++] = car; // Access Violation
        }

        Car* begin(){return cars;};

        Car* end(){ return cars + numCars;} 

setNumCars (int count) {numCars = count;}

    private:
        static const int DEFAULT_MAX_CARS = 10;
        Car* cars;
        int numCars;
};

/**********************************Car.h**********************/
#include <cstdlib>
#include <string>

using namespace std;


class Car{
    public:

        Car()
            : year(0), make(""), model("")
        {}

        Car(int year, string make, string model)
            : year(year), make(make), model(model)
        {}      

        string getMake() const {return make;}
        void setMake(string make){this->make=make;}

        string getModel() const {return model;}
        void setModel(string model){this->model=model;}

        int getYear() const {return year;}
        void setYear(int year){this->year=year;}

    private:
        int year;
        string make;
        string model;       
};


ostream& operator<< (ostream& out, const Car& car)
{
    out << car.getYear() << " " << car.getMake() << " " << car.getModel();
    return out;
}

/**********************************Main.cpp**********************/
#include &lt;cstdlib&gt;
#include &lt;iostream&gt;
#include "Dealer.h"

using namespace std;

void addCar(Dealer& d);

int main(int argc, char *argv[])
{
    Dealer d;

    addCar(d);  

    system("PAUSE");
    return EXIT_SUCCESS;
}

void addCar(Dealer& d)
{
    d = Dealer();

    d.addCar(Car(2007, "Honda", "Civic"));

    cout << d.getTotalCars() << " total cars" << endl;
}

Ответы [ 6 ]

4 голосов
/ 22 сентября 2009
void addCar(const Car& car)
{
     cars[numCars++] = car; // Access Violation
}

Вы никогда не инициализируете numCars - он содержит какое-то значение из кучи, которое почти наверняка не равно нулю. Это заставляет вас читать за концом машинного массива и в недоступную память. Вы должны установить numCars на 0 в вашем конструкторе.

Кроме того, у вас должны быть некоторые проверки в addCar, чтобы не переполнять массив cars.

EDIT:

Есть некоторые другие проблемы с кодом - например, "d = Dealer ();" создает нового дилера и перезаписывает тот, который вы передаете по ссылке на addCars, что, кажется, не то, что вы хотите сделать.

Попробуйте добавить некоторую дополнительную трассировку в конструктор / деструкторы, чтобы убедиться, что конструкторы, которые, по вашему мнению, вызываются, действительно являются - похоже, Dealer () должен вызывать конструктор с указанным вами аргументом по умолчанию, но если нет, он получает конструктор по умолчанию.

1 голос
/ 22 сентября 2009

Может быть я не вижу, но где вы изначально устанавливаете numCars?

1 голос
/ 22 сентября 2009

Ничто в приведенном выше коде не инициализирует Dealer :: numCars. Следовательно, это может быть любой случайный мусор.

1 голос
/ 22 сентября 2009

Вы нигде не инициализируете numCars, вы должны установить его в 0:

Dealer(int maxCars = DEFAULT_MAX_CARS) :
numCars(0)
{
    cars = new Car[maxCars];
}

Вы должны использовать сырые указатели? Почему бы не обернуть его и использовать вместо него std::vector?

0 голосов
/ 22 сентября 2009
cars[numCars++] = car; // Access Violation

Я не вижу проблем в размещенном коде. Может быть проблема в другом месте?

Возможно, вы можете попробовать следующее:

  • измените массивы на векторные и попробуйте использовать at (), чтобы перехватить исключение out_of_range. что-то вроде:

       std::vector<int> myVec;
       try
       {
        int x = myVec.at(0);
    
       }
       catch(std::out_of_range& oor)
       {
            printf("\nout of range ");
       }
    
0 голосов
/ 22 сентября 2009

Для меня это выглядит как утечка памяти , поскольку вы не освобождаете предыдущую память, удерживаемую указателем cars :

setNumCars(0) {cars = new Car[maxCars];}

, и этокод должен защищать от переполнения:

void addCar(const Car& car)        
{                                
   cars[numCars++] = car; // Access Violation        '
}

, выполняя что-то вроде этого:

void addCar(const Car& car)        
{                                
   if (numCars < maxCars)
      cars[numCars++] = car;        '
   else
      // throw and exception .....
      // or better still grow the cars buffer
}
...