Нарушение доступа к динамическому массиву C ++
-
12-09-2019 - |
Вопрос
**** Извините за путаницу относительно numCars в исходном сообщении.Я изменил код, чтобы он соответствовал оригиналу ******
Следующая учебная программа представляет собой упрощенную версию исходной задачи, но она фокусируется на проблеме, которую мне еще предстоит решить.Существует 2 класса и основной метод решения этой задачи, и эти 2 класса состоят из класса Дилера и класса автомобиля.Класс Dealer имеет указатель private Car*, который инициализируется динамическим массивом в конструкторе Dealer.Ошибка возникает в основном методе при вызове метода addCar Дилера.В основном методе я намеренно передаю переменную Dealer в метод addCar (Dealer& d), чтобы имитировать структуру исходного приложения.Затем метод addCar вызывает метод addCar Дилера (const Car& car), где нарушение доступа происходит, когда я выполняю cars[numCars++]=car;Можете ли вы объяснить, почему cars[numCars++]=car приводит к нарушению доступа
/**********************************Dealer.h**************************/
#include <cstdlib>
#include "Car.h"
using namespace std;
class Dealer
{
public:
Dealer(int maxCars = DEFAULT_MAX_CARS)
:numCars(0) {автомобили = новая машина [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 = количество;}
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 <cstdlib>
#include <iostream>
#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;
}
Решение
void addCar(const Car& car)
{
cars[numCars++] = car; // Access Violation
}
Вы никогда не инициализируете numCars - он содержит некоторое значение из кучи, которое почти наверняка ненулевое.Это приводит к чтению за пределы конца массива cars в недоступную память.Вы должны установить numCars равным 0 в вашем конструкторе.
Вдобавок ко всему, у вас должны быть некоторые проверки в addCar, чтобы вы не переполняли массив cars.
Редактировать:
Есть некоторые другие проблемы с кодом - например, "d = Dealer();" создает нового дилера и перезаписывает тот, который вы передаете по ссылке на addCars, что, похоже, не то, что вы хотите сделать.
Попробуйте добавить некоторую дополнительную трассировку к конструктору / деструкторам, чтобы убедиться, что вызываемые конструкторы, по вашему мнению, на самом деле являются таковыми - похоже, что Dealer() должен вызывать конструктор с указанным вами аргументом по умолчанию, но если нет, то он получает конструктор по умолчанию.
Другие советы
Вы не выполняете инициализацию numCars
в любом месте вы должны установить его равным 0:
Dealer(int maxCars = DEFAULT_MAX_CARS) :
numCars(0)
{
cars = new Car[maxCars];
}
Обязательно ли вам использовать необработанные указатели?Почему бы не завернуть его и не использовать std::vector
вместо этого?
Ничто в приведенном выше коде не инициализирует Dealer::numCars.Следовательно, это может быть любой случайный мусор.
Может быть, я этого не вижу, но где вы изначально устанавливаете numCars?
Это выглядит как утечка памяти для меня с тех пор вы не освобождаете предыдущую память, хранящуюся в Автомобили указатель:
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
}
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 "); }