【问题标题】:C++ memory access errorC++ 内存访问错误
【发布时间】:2014-10-03 17:58:41
【问题描述】:

我在尝试调用函数 Organization::addWorker 时遇到问题,它似乎在内存释放步骤(操作员 delete[])上失败,但指针显示的内存已被释放。

调用栈:

lab1.exe!Person::setName(char * thename)第 80 行 C++

lab1.exe!Coworker::operator=(Coworker & theco)Line 303 C++

lab1.exe!Organization::addWorker(Coworker & theworker)Line 404 C++

lab1.exe!main()第 97 行 C++

   #include <string>
    #include "class_Date.h"
    
    using namespace std;
    
    enum workNec { worker, manager, employer };
    
    class Person {
    
        char* name; 
        char* surname;
        Date bd;
    
    public:
    
        Person();
        Person(char* thename, char* thesurname, Date thebd);
        Person(const Person &theperson);
        ~Person();
    
        char* getName() { return name; }
        char* getSurname() { return surname; }
        Date getBD() { return bd; }
    
        void getFullInfo();
    
        Person & setName(char* thename);
        Person & setSurname(char* thesurname);
        Person & setBD(int dd, int mm, int yy);
        Person & setBD(Date thebd);
    
        Person & operator=(Person& thepers);
    
    };
    
    Person::Person() { 
    
        name = new char [1];
        strcpy(name, "");
        surname = new char[1];
        strcpy(surname, "");
    
    }
    
    Person::Person(char* thename, char* thesurname, Date thebd) { 
    
        name = new char [strlen(thename)+1];
        surname = new char [strlen(thesurname)+1];
        strcpy(name, thename);
        strcpy(surname, thesurname);
        bd = thebd;
    
    }
    Person::Person(const Person & theperson) { 
    
        name = new char[strlen(theperson.name) + 1];
        surname = new char[strlen(theperson.surname) + 1];
        strcpy(name, theperson.name);
        strcpy(surname, theperson.surname);
        bd = theperson.bd;
    
    }
    Person::~Person() {
    
        cout << "Destructing Person " << name << endl;
        delete [] name;
        delete [] surname;
    
    
    }
    
    void Person::getFullInfo() { 
        
        cout << name << " " << surname << " "; bd.getFullDate(); 
    
    }
    
    Person & Person::setName(char* thename)  { 
    
        delete [] name;
        name = new char[strlen(thename) + 1]; strcpy(name, thename); 
        return *this; 
    
    }
    
    Person & Person::setSurname(char* thesurname) { 
        
        delete [] surname;
        surname = new char[strlen(thesurname) + 1]; strcpy(surname, thesurname);
        return *this; 
    
    }
    Person & Person::setBD(int dd, int mm, int yy) { 
        
        bd.setDD(dd); bd.setMM(mm); bd.setYY(yy); 
        return *this; 
    
    }
    
    Person & Person::setBD(Date thebd) { 
    
        bd = thebd; 
        return *this; 
    
    }
    
    Person & Person::operator=(Person& thepers) {
    
        delete [] this->name;
        delete [] this->surname;
        this->name = new char[strlen(thepers.name) + 1];
        this->surname = new char[strlen(thepers.surname) + 1];
        strcpy(this->name, thepers.name);
        strcpy(this->surname, thepers.surname);
        bd = thepers.bd;
        return *this;
    }
    
    //*************************************************************************************************
    
    class Position {
    
        char* department;
        workNec wn;
        int salary;
    
    public:
    
        Position();
        Position(char *thedept, workNec thewn, int thesalary);
        Position(const Position & thepos);
        ~Position();
    
        char* getDept() { return department; }
        workNec getWorkNec() { return wn; }
        int getSalary() { return salary; }
    
        void getFullInfo();
    
        Position & setDept(char* dept);
        Position & setWorkNec(workNec nec);
        Position & setSalary(int sal);
    
    };
    
    
    Position::Position() {
    
        department = new char[1];
        strcpy(department, "");
    
    }
    
    Position::Position(char *thedept, workNec thewn, int thesalary) { 
    
        department = new char[strlen(thedept) + 1];
        strcpy(department, thedept);
        wn = thewn; 
        salary = thesalary; 
    
    }
    
    Position::Position(const Position & thepos) { 
    
        department = new char[strlen(thepos.department)+1]; 
        strcpy(department, thepos.department);
        wn = thepos.wn; 
        salary = thepos.salary; 
    
    }
    
    Position::~Position() { 
    
        cout << endl << "Deleting Position " << department << endl;
        delete [] department;
    
    }
    
    void Position::getFullInfo() { 
        
        cout << department << " " << wn << " " << salary << " "; 
    
    }
    
    Position & Position::setDept(char* dept) { 
    
        delete [] department;
        department = new char[strlen(dept)+1];
        strcpy(department, dept);
        return *this; 
    
    }
    Position & Position::setWorkNec(workNec nec) {
        
        wn = nec; 
        return *this; 
    
    }
    Position & Position::setSalary(int sal) { 
        
        salary = sal; 
        return *this; 
    
    }
    
    //*************************************************************************************************
    
    class Coworker {
    
        Person person;
        Position position;
    
    public:
    
        Coworker();
        Coworker(Person &theperson, Position &thepos);
        Coworker( Coworker & theco);
        ~Coworker();
    
        Person getPerson() { return person; }
        Position getPosition() { return position; }
    
        void getFullInfo();
    
        Coworker & setPerson(Person &per);
        Coworker & setPosition(Position &pos);
    
        Coworker & operator=(Coworker& theco);
        
    };
    
    Coworker::Coworker() {
    
    }
    
    Coworker::Coworker(Person &theperson, Position &thepos) { 
        
        person.setBD(theperson.getBD());
        person.setName(theperson.getName());
        person.setSurname(theperson.getSurname());
        position.setDept(thepos.getDept());
        position.setSalary(thepos.getSalary());
        position.setWorkNec(thepos.getWorkNec());
    
    }
    
    Coworker::Coworker(Coworker & theco) { 
    
        Person pers;
        pers = theco.person;
        Position pos = theco.position;
    
        person.setBD(pers.getBD());
        person.setName(pers.getName());
        person.setSurname(pers.getSurname());
        position.setDept(pos.getDept());
        position.setSalary(pos.getSalary());
        position.setWorkNec(pos.getWorkNec());
    
    }
    
    Coworker::~Coworker() {
    
    
        cout << endl << "Deleting Coworker " << endl;
    
    }
    
    void Coworker::getFullInfo() { 
        
        person.getFullInfo(); cout << " ";  position.getFullInfo(); 
    
    }
    
    Coworker & Coworker::setPerson(Person &per) { 
        
        Person tper = per;
        person.setBD(tper.getBD());
        person.setName(tper.getName());
        person.setSurname(tper.getSurname());
        return *this; 
    
    }
    Coworker & Coworker::setPosition(Position &pos) { 
        
        Position tpos = pos;
        position.setDept(tpos.getDept());
        position.setSalary(tpos.getSalary());
        position.setWorkNec(tpos.getWorkNec());
        return *this; 
    
    }
    
    Coworker & Coworker::operator=(Coworker& theco) {
    
        Person pers;
        pers = theco.person;
        Position pos;
        pos = theco.position;
    
        person.setBD(pers.getBD());
        person.setName(pers.getName());
        person.setSurname(pers.getSurname());
        position.setDept(pos.getDept());
        position.setSalary(pos.getSalary());
        position.setWorkNec(pos.getWorkNec());
        return *this;
    }
    
    class Organization {
    
        char* title;
        Coworker * coworker;
        int cwAmount;
    
    public:
    
        Organization();
        Organization(char* thetitle, Coworker * theco, int thecw);
        Organization(const Organization & org);
        ~Organization();
    
        void addWorker(Coworker &theworker);
    
        char* getTitle() { return title; }
        int getAmount() { return cwAmount; }
        Coworker * getCoworker() { return coworker; }
    
        Organization & setTitle(char* tit);
        Organization & setAmount(int am);
        Organization & setCoworker(Coworker *theco);
    
        void getFullInfo();
        void getShortInfo();
    
    };
    
    //*************************************************************************************************
    
    Organization::Organization() {
    
        title = new char[1];
        strcpy(title, "");
        cwAmount = 0;
        coworker = new Coworker[0];
    
    }
    
    
    Organization::Organization(char* thetitle, Coworker * theco, int thecw) { 
        
        title = new char[strlen(thetitle) + 1];
        strcpy(title, thetitle);
    
        cwAmount = thecw; 
        coworker = new Coworker[cwAmount];
    
        for (int i = 0; i < cwAmount; i++) {
    
            coworker[i].setPerson(theco[i].getPerson());
            coworker[i].setPosition(theco[i].getPosition());
    
        }
    
    }
    
    Organization::Organization(const Organization & org) { 
        
        title = new char[strlen(org.title) + 1];
        strcpy(title, org.title);
    
        cwAmount = org.cwAmount; 
    
        coworker = new Coworker[cwAmount];
    
        for (int i = 0; i < cwAmount; i++) {
    
            coworker[i].setPerson(org.coworker[i].getPerson());
            coworker[i].setPosition(org.coworker[i].getPosition());
    
        }
    
    }
    
    Organization::~Organization() { 
        
    
        cout << endl << "Deleting Organization " <<title<< endl;
        delete [] coworker;
    
    };
    
    void Organization::addWorker(Coworker &theworker) {
        cout << "a";
    
        Coworker * new_coworker = new Coworker[cwAmount + 1];
    
        for (int i = 0; i < cwAmount; i++) new_coworker[i] = coworker[i];
    
        cwAmount++;
    
        new_coworker[cwAmount] = theworker;
    
        delete [] coworker;
    
        coworker = new_coworker;
    
    }
    
    void Organization::getFullInfo() {
    
        std::cout << title << " " << cwAmount << endl;
        for (int i = 0; i < cwAmount; i++) {
            coworker[i].getPerson().getFullInfo();
            cout << " ";
            coworker[i].getPosition().getFullInfo();
            cout << endl;
        }
    
    }
    
    void Organization::getShortInfo() {
    
        int total = 0;
        for (int i = 0; i < cwAmount; i++) {
    
            total += coworker[i].getPosition().getSalary();
    
        }
    
        std::cout << this->title << " " << total << std::endl;
    
    }
    
    Organization & Organization::setTitle(char* tit) { 
        
        title = new char[strlen(tit)+1]; 
        strcpy(title, tit);
        return *this; 
    
    }
    
    Organization & Organization::setAmount(int am) { 
        
        cwAmount = am; 
        return *this; 
    }
    
    Organization & Organization::setCoworker(Coworker *theco) { 
    
        delete [] coworker;
        coworker = new Coworker [cwAmount];
    
        for (int i = 0; i < cwAmount; i++) {
    
            coworker[i].setPerson(theco[i].getPerson());
            coworker[i].setPosition(theco[i].getPosition());
    
        }
    
        return *this; 
    
    }

ma​​in.cpp:

#define _CRT_SECURE_NO_WARNINGS

#include "classes_v23.h"

using namespace std;

int main() {
    {
    Date d1;

    Date d2(19, 04, 1995);

    Date d3 = d2;

    d1.getFullDate(); cout << endl;
    d2.getFullDate(); cout << endl;
    d3.getFullDate(); cout << endl;

    //******************************

    Person pers1;

    pers1.setBD(d2);
    pers1.setName("Ihor");
    pers1.setSurname("Pukish");

    Person pers2("name2", "surname2", d2);
    Person pers3 = pers2;

    pers1.getFullInfo(); cout << endl;
    pers2.getFullInfo(); cout << endl;
    pers3.getFullInfo(); cout << endl;

    //******************************

    Position pos1;

    pos1.setDept("IASA");
    pos1.setSalary(100);
    pos1.setWorkNec(employer);

    Position pos2("dept2", worker, 200);
    Position pos3 = pos2;

    pos1.getFullInfo(); cout << endl;
    pos2.getFullInfo(); cout << endl;
    pos3.getFullInfo(); cout << endl;

    //******************************

    Coworker co1;
    co1.setPerson(pers1);
    co1.setPosition(pos1);

    Coworker co2(pers2, pos2);
    Coworker co3 = co2;
    Coworker co4(pers1, pos1);

    co1.getFullInfo(); cout << endl;
    co2.getFullInfo(); cout << endl;
    co3.getFullInfo(); cout << endl;

    //******************************

    Coworker * cow = new Coworker[3];
    cow[0] = co1;
    cow[1] = co2;
    cow[2] = co3;

    Organization org1("title", cow, 3);
    org1.addWorker(co4);
}
system("pause");
}

【问题讨论】:

  • 您错过了几个operator=。您的operator= 不支持a=a。你应该使用std::string
  • 我只是想评论一下我喜欢这种方式,你组织你的代码......除此之外,我希望你显示行号......如果你能指出错误是哪一行来自它会有所帮助......
  • 我建议如果要使用 char 数组,在使用 delete 之后,您应该将 NULL 或 0 或 nullptr 分配给指针变量。 what exactly is nullptris it still save to delete nullptr
  • @Dark Falcon ,该任务只需要使用指向 char 数组的指针,而不是字符串。我似乎不需要比我使用的更多的运算符“=”。还是我弄错了?我需要在哪里使用我的操作符来表示“a=a”?
  • @ІгорПукіш:你需要更多。您在每个有 char* 成员的类上都需要它们(它们在 PositionOrganization 中缺失)。编译器生成的不起作用。这就是为什么我推荐使用std::string;有了它,编译器生成的就可以了。

标签: c++ memory


【解决方案1】:

我认为问题是:

void Organization::addWorker(Coworker &theworker) {
    cout << "a";

    Coworker * new_coworker = new Coworker[cwAmount + 1];

    for (int i = 0; i < cwAmount; i++) new_coworker[i] = coworker[i];

    cwAmount++;

    new_coworker[cwAmount] = theworker;

    delete [] coworker;

    coworker = new_coworker;

}

请注意,您在分配 theworker 之前增加了 cwAmount。但是我认为你应该先分配,然后增加。空元素位于预增量索引处。

这也可以使用矢量更容易地完成。

【讨论】:

  • 是的,你是对的。我使用了不在范围内的数组的索引。不知道我怎么没注意到。
  • 感谢所有帮助过的人
【解决方案2】:

首先,您包含&lt;string&gt;,但您没有使用&lt;string&gt; 提供的功能,即std::string。既然你说你必须使用C风格的字符串,正确的标题是&lt;cstring&gt;,而不是&lt;string&gt;

其次,如果传递了NULL,甚至是伪造的指针,此函数将不起作用:

Person::Person(char* thename, char* thesurname, Date thebd) { 
        name = new char [strlen(thename)+1];   // undefined behavior if NULL is passed
        surname = new char [strlen(thesurname)+1];  // undefined behavior if NULL is passed
        //...
    }

该函数应该检查 NULL 指针参数。但即便如此,也存在传递一个未指向有效缓冲区的指针的风险。

现在,正如其他人所说,您需要为每个具有动态分配内存指针的类正确编写赋值运算符。

让我们从Person 赋值运算符开始:

 Person & Person::operator=(Person& thepers) {
        delete [] this->name;
        delete [] this->surname;
        this->name = new char[strlen(thepers.name) + 1];
        this->surname = new char[strlen(thepers.surname) + 1];
        strcpy(this->name, thepers.name);
        strcpy(this->surname, thepers.surname);
        bd = thepers.bd;
        return *this;
    }

这不仅是多余的(大部分代码都在复制构造函数中),它失败的原因如下:

  1. delete[]的名字和姓氏。如果下面的new[] 抛出异常会发生什么?在确保 new 不会失败之前,您已经通过删除数据弄乱了对象。
  2. 您不检查自我分配。
  3. 该项目应作为 const 引用传递。

修复的方法很简单,我建议您对所有其他课程都这样做。

 #include <algorithm>
 //...
 Person & Person::operator=(const Person& thepers) 
 {
      Person other(thepers);
      swap(*this, other);
      return *this;
 }

 void Person::swap(Person& left, Person& right)
 {
      std::swap(left.name, right.name);
      std::swap(left.surname, right.surname);
      std::swap(left.bd, right.bd);
  }

就是这样,没有别的了。这称为copy/swap 成语。只要你编写了一个有效且正确的复制构造函数,上面的代码不仅可以正确复制,还可以解决自赋值和过早销毁成员的问题。

它的工作方式是创建一个临时的,通过将你的与临时的交换来为你自己“窃取”临时的东西,然后让临时的东西和你的旧东西一起死掉。通俗地说就是正在发生的事情。

请为其他课程执行此操作。例如Coworker:

Coworker & Coworker::operator=(const Coworker& theco) 
{
   Coworker temp(theco);
   swap(*this, temp);
   return *this;
}

void Coworker::swap(Coworker& left, Coworker& right)
{
    std::swap(left.person, right.person);
    std::swap(left.position, right.position);
}

此外,您的 Organization 类缺少赋值运算符。只需使用上述技术添加一个即可。

此外,您的 setName 函数也会在重新分配之前删除内存:

Person & Person::setName(char* thename)  { 
    delete [] name;
    name = new char[strlen(thename) + 1]; strcpy(name, thename); 
    return *this; 
}

这也可以通过先分配给一个临时的,然后再分配 在函数末尾临时:

Person & Person::setName(char* thename)  
{ 
    char *tempname = new char[strlen(thename) + 1]; 
    strcpy(tempname, thename); 
    delete [] name;
    name = tempname;
    return *this;
}

【讨论】:

  • 感谢您的提示,它们非常有用。唯一的事情是我不允许使用外部功能,例如swap,等等,因为它只是引入lab。
  • @ІгорПукіш 您不能使用“外部函数”,但您使用的是“外部”函数strcpy()strlen()
  • 我的意思是我不能在我的课堂上使用不同的方法,只有提到的地方。
猜你喜欢
  • 2016-06-30
  • 2016-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多