Mushy
Mushy

Reputation: 2645

Destructor called on std::vector<Class type> invalidating for_each

I've been doing some reading about delete[], new[], what-is-the-rule-of-three, deallocating-objects-stored-in-a-vector, delete-vector-class-member and encountering an

Exception thrown: read access violation.

I have defined a base class

class Person
{
private:
    std::string name;
    int age;
    static int cur_id;
public:
    Person() {}
    Person(std::string new_name, int new_age) : name(new_name), age(new_age) { cur_id += 1; }
    virtual ~Person() {}
    void setname(std::string name) { this->name = name; }
    std::string getname() { return name; }
    int getage() { return age; }
    void setage(int age) { this->age = age; }
    int get_id() { return cur_id; }

    virtual void getdata(void) = 0;
    virtual void putdata(void) = 0;
};

Derived class

class Professor : private Person
{
private:
    int publications;
    Professor* prof;
public:
    Professor() {}
    Professor(std::string new_name, int new_age, int new_pubs) : Person(new_name, new_age) { this->publications = new_pubs; }
    ~Professor() override { delete prof; }
    void getdata() override 
    {
        std::vector<std::string> prof_input = get_input();
        std::cout << prof_input[0] << "\n";
        std::cout << std::stoi(prof_input[1]) << "\n";
        std::cout << std::stoi(prof_input[2]) << "\n";
        prof = new Professor(prof_input[0], std::stoi(prof_input[1]), std::stoi(prof_input[2]));
    }
    void putdata() override 
    {
        std::cout << prof->getname() << " " << prof->getage() << " " << prof->publications << " " << prof->get_id();
    }
};

and have defined main

int main()
{
    int size; 

    std::cin >> size;

    std::cin.ignore();

    Professor* prof = new Professor();

    std::vector<Professor> prof_vec;

    for (int i = 0; i < size; i++)
    {
        int which;
        std::cin >> which;
        std::cin.ignore();

        switch (which)
        {
        case 1: 
        {
            prof->getdata();
            prof_vec.push_back(*prof);
        }
        break;
        case 2:
        {
            // something else
        }
        break;
        }
    }

    for (auto prof : prof_vec)
    {
        prof.putdata();
    }  <<< ------------------- Things so south here

    delete prof;

    fgetc(stdin);

    return 0;
}

What I figured was happening is (assuming only one element in the vector), once the call to putdata() exited the block, the destructor call delete prof occurs followed by

this->prof was 0xCDCDCDCD.

I'm attempting to delete an object that doesn't exist. If I want to be sure to properly delete, what should I be doing to ensure no memory leaks even with such a simple example?

Upvotes: 0

Views: 92

Answers (2)

James Dong
James Dong

Reputation: 404

The member Professor* prof is not initialized in the constructor Professor(), and is only initialized in getdata();

When the code goes to case 2, if there is not any call to getdata(), then the prof is left uninitialized.

The 0xCDCDCDCD indicates an uninitialized value in debug mode.

Upvotes: 2

Barry
Barry

Reputation: 302852

You're violating the rule of 3/5/0:

class Professor : private Person
{
private:
    Professor* prof;
public:
    // ...
    ~Professor() override { delete prof; }
};

If you provide one of the special member functions, you should provide all of the special member functions. In this case, your copy constructor just member-wise copies the Professor* and now you have two different objects trying to delete the same pointer.

Prefer the rule of 0:

class Professor : private Person
{
private:
    std::unique_ptr<Professor> prof;
public:
    // ...
    ~Professor() = default;
};

Upvotes: 4

Related Questions