简体   繁体   中英

C++: How do I correct the read access violation that my code does

I am beginner at C++ and have been trying to figure a few things out on my own. I am supposed to be writing a code for a function that accepts a vector of pointers to a certain object, go through the list, and delete the invalid date from the list. So far, when testing, I keep getting an error that reads: "Exception thrown: read access violation" and I have been trying for the past few days to find the error, to no avail.

Here's my code:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

class Reminder
{
private:
    int m_day;
    int m_month;
    string m_description;
    bool value;

public:

    Reminder(int day, int month, string description) : m_day(day), m_month(month), m_description(description)
    {

    }

    string toString()
    {
        stringstream sin;
        sin << m_month << "/" << m_day << ": " << m_description<<endl;
        return sin.str();
    }

    int getDay()
    {
        int day = m_day;
        return day;
    }

    int getMonth()
    {
        int month = m_month;
        return month;
    }



};

vector<Reminder*> removeInvalidDate(vector<Reminder*>& list)
{
    for (int count = 0; count < list.size(); count++)
    {
        if ((list[count]->getDay() < 1) || (list[count]->getDay() > 31))
            delete list[count];
        if ((list[count]->getMonth() < 1) || (list[count]->getMonth() > 12))
            delete list[count];
        else
            ;
    }

    return list;
}

int main()
{
    Reminder reminder1(7, 16, "Final Exam Due");
    Reminder reminder2(7, 4, "Independence Day Holiday");
    Reminder reminder3(1, 1, "Start of the New Year");
    Reminder reminder4(7, 30, "My Birthday");
    Reminder reminder5(1, -9, "Impossible Day1");
    Reminder reminder6(0, 0, "Impossible Day0");
    Reminder reminder7(0, 35, "Impossible day3");
    Reminder reminder8(13, 0, "Impossible");

    Reminder* pRe;
    pRe = new Reminder(reminder1);

    vector<Reminder*> list;

    list.push_back(pRe);

    pRe = new Reminder(reminder2);
    list.push_back(pRe);

    pRe = new Reminder(reminder3);
    list.push_back(pRe);

    pRe = new Reminder(reminder4);
    list.push_back(pRe);

    pRe = new Reminder(reminder5);
    list.push_back(pRe);

    pRe = new Reminder(reminder6);
    list.push_back(pRe);

    pRe = new Reminder(reminder7);
    list.push_back(pRe);

    pRe = new Reminder(reminder8);
    list.push_back(pRe);

    removeInvalidDate(list);

    return 0;
}

I think that the issue is either in setting up and passing the vector or in one of the class constructors.

If both the day and the month are invalid, you're deleting list[count] twice

if ((list[count]->getDay() < 1) || (list[count]->getDay() > 31))
    delete list[count];
if ((list[count]->getMonth() < 1) || (list[count]->getMonth() > 12))
    delete list[count];

I think that the issue is either in setting up and passing the vector or in one of the class constructors.

Well, you can test both hypothesis. And you should actually do this!

Firstly, you can test whether your constructors are causing a problem by simplifying your code to use vector<int> . Just say the integer value is the day and leave out the month part for now.

Secondly, you can set up the minimal vector with the simplest possible code - and just one element. Or zero elements. And then add elements back until the problem recurs.

This kind of work, testing your understanding of the code, is perfectly normal and a good habit to start.

Neither of those hypotheses will fix your current problem, but I'd encourage you to go back and do them anyway.

This code

    if ((list[count]->getDay() < 1) || (list[count]->getDay() > 31))
        delete list[count];
    if ((list[count]->getMonth() < 1) || (list[count]->getMonth() > 12))
        delete list[count];
    else
        ;

has two main problems. The first is that the layout suggests you intend

    if (X)
        A;
    elif (Y)
        B;
    else
        ;

but C++ doesn't have an elif . If you don't want to remove the same element twice, it should be something like

    if ((list[count]->getDay() < 1) || (list[count]->getDay() > 31))
    {
        delete list[count];
        continue;
    }
    if ((list[count]->getMonth() < 1) || (list[count]->getMonth() > 12))
    {
        delete list[count];
        continue;
    }

(or if () {... } else if () {... } or whatever).

The second and more serious problem is that delete list[count] is not how you remove elements from any container in C++. It's roughly how you'd do it in Python. In C++ though, after delete list[count] , the element list[count] still exists but is a dangling pointer to the storage you just delete -d, and may never legally be dereferenced. Since the very next thing you do is dereference it (for the month check), this causes your read access violation.

Any good book will tell you that std::vector::erase is how you remove elements from a vector, and that you should prefer std::remove_if to that, and that you should avoid storing (owning) raw pointers in containers in the first place.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM