Reputation: 15
I'm taking a C++ class but I'm not completely new to programming as I know a good deal of Java and some Python. This is something I have never seen before: I have a program that supposed to inventory animals on an ark and age them by 1 month and simulate the population growth on the ark. I went through with the debugger and found it works fine until the second fish object goes through the ageOneMonth method, then I get an exception
"Exception thrown at 0x00007FF779B38CBB in noahsArkApp.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF."
The program exits with (process 20984) exited with code -1073741819.
What's even more weird is each time this happens my Norton antivirus shows a popup "Potential Threat Blocked" The action described in the details is "suspicious process attempted to modify security of a file protected by Data Protector". What could be going on here? How do I fix this exception? Do I need to disable Norton?
#include <iostream>
#include <string>
#include <vector>
#include <memory> // for smart pointers? Googled for a fix to memory issue but still having problems :(
#include <cstdlib> // for srand() and rand() functions
#include <ctime> // for time() function
using namespace std;
// enum classes to limit options for type and gender
enum class Type { MAMMAL, BIRD, FISH };
enum class Gender { FEMALE, MALE };
class Animal {
protected:
Type type;
string species;
Gender gender;
int ageInMonths;
public:
Type getType() { return type; }
string getName() { return species; }
Gender getGender() { return gender; }
int getAgeInMonths() { return ageInMonths; }
Animal(Type _type, string _name, Gender _gender, int _ageInMonths) : type(_type), species(_name), gender(_gender), ageInMonths(_ageInMonths) {};
virtual void ageOneMonth() {
ageInMonths++;
}
virtual void giveBirth(vector<unique_ptr<Animal>>& animals) {
// Default implementation does nothing
}
virtual void identifyAnimal() const {
string genderStr = (gender == Gender::MALE) ? "male" : "female";
cout << "I am a " << genderStr << " " << species << ", " << ageInMonths << " months old." << endl;
}
};
class Mammal : public Animal {
public:
Mammal(Type _type, string _name, Gender _gender, int _ageInMonths) : Animal(Type::MAMMAL, _name, _gender, _ageInMonths) {}
virtual void giveBirth(vector<unique_ptr<Animal>>& animals) override {
if (gender == Gender::FEMALE && ageInMonths % 12 == 0) {
Gender newbornGender = (rand() % 2 == 0) ? Gender::MALE : Gender::FEMALE;
animals.push_back(make_unique<Mammal>(getType(), getName(), newbornGender, 0));
}
}
};
class Bird : public Animal {
public:
Bird(Type _type, string _name, Gender _gender, int _ageInMonths) : Animal(Type::BIRD, _name, _gender, _ageInMonths) {}
virtual void giveBirth(vector<unique_ptr<Animal>>& animals) override {
if (gender == Gender::FEMALE && ageInMonths % 9 == 0) {
Gender newbornGender = (rand() % 2 == 0) ? Gender::MALE : Gender::FEMALE;
animals.push_back(make_unique<Bird>(getType(), getName(), newbornGender, 0));
}
}
};
class Fish : public Animal {
public:
Fish(Type _type, string _name, Gender _gender, int _ageInMonths) : Animal(Type::FISH, _name, _gender, _ageInMonths) {}
virtual void giveBirth(vector<unique_ptr<Animal>>& animals) override {
if (gender == Gender::FEMALE && ageInMonths % 6 == 0) {
Gender newbornGender = (rand() % 2 == 0) ? Gender::MALE : Gender::FEMALE;
animals.push_back(make_unique<Fish>(getType(), getName(), newbornGender, 0));
}
}
};
int main() {
srand((unsigned int)time(0));
vector<unique_ptr<Animal>> animals;
// Add initial animals to the ark
animals.push_back(make_unique<Mammal>(Type::MAMMAL, "Cat", Gender::FEMALE, 11));
animals.push_back(make_unique<Mammal>(Type::MAMMAL, "Cat", Gender::MALE, 10));
animals.push_back(make_unique<Mammal>(Type::MAMMAL, "Dog", Gender::FEMALE, 12));
animals.push_back(make_unique<Mammal>(Type::MAMMAL, "Cat", Gender::MALE, 9));
animals.push_back(make_unique<Fish>(Type::FISH, "Goldfish", Gender::FEMALE, 5));
animals.push_back(make_unique<Fish>(Type::FISH, "Goldfish", Gender::MALE, 5));
animals.push_back(make_unique<Fish>(Type::FISH, "Shark", Gender::FEMALE, 6));
animals.push_back(make_unique<Fish>(Type::FISH, "Shark", Gender::MALE, 6));
animals.push_back(make_unique<Bird>(Type::BIRD, "Eagle", Gender::FEMALE, 8));
animals.push_back(make_unique<Bird>(Type::BIRD, "Eagle", Gender::MALE, 11));
animals.push_back(make_unique<Bird>(Type::BIRD, "Parakeet", Gender::FEMALE, 17));
animals.push_back(make_unique<Bird>(Type::BIRD, "Parakeet", Gender::MALE, 13));
int months = 0;
while (true) {
cout << "\nYou have been on the ark for " << months << " months. What would you like to do?" << endl;
cout << "1 - Let another month pass" << endl;
cout << "2 - Check inventory" << endl;
cout << "3 - Quit" << endl;
int choice;
cin >> choice;
if (choice == 1) {
months++;
// Age all animals by one month and let them give birth
for (auto& animal : animals) {
animal->ageOneMonth();
animal->giveBirth(animals);
}
}
else if (choice == 2) {
// Display inventory
cout << "\nInventory:" << endl;
int count = 1;
for (const auto& animal : animals) {
cout << "Animal #" << count++ << ": ";
animal->identifyAnimal();
}
}
else if (choice == 3) {
// Clean up memory
animals.clear();
break;
}
}
return 0;
}
Upvotes: 1
Views: 224
Reputation: 73219
I don't know what Norton is on about, but as far as why your program is crashing, I believe it is because your giveBirth()
function is modifying the animals
vector while the for-loop in main()
is iterating over that same vector, and that is a no-no because it invalidates the iterator object.
To test my theory, I replaced the choice==1
code with the following:
months++;
// Age all animals by one month and let them give birth
vector<unique_ptr<Animal>> temp;
for (auto& animal : animals) {
animal->ageOneMonth();
animal->giveBirth(temp);
}
// Now that we are done iterating over animals
// we can go ahead and add the new infants to the vector
for (auto& animal : temp) {
animals.push_back(std::move(animal));
}
.... and with that change I can no longer get the program to crash.
Upvotes: 2