[英]C++ memory access error
嘗試調用函數Organization :: addWorker時遇到問題,它似乎在內存釋放步驟,操作符delete []上失敗,但是指針已顯示的內存已被釋放。
調用堆棧:
Lab1.exe!Person :: setName(char * thename)行80 C ++
lab1.exe!Coworker :: operator = {Coworker&theco)線303 C ++
lab1.exe!Organization :: addWorker(Coworker&theworker)Line 404 C ++
main1)行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;
}
main.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");
}
我相信問題是:
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;
}
請注意,您增加cwAmount
分配之前theworker
。 但是我認為您應該先分配,然后遞增。 空元素位於預遞增索引處。
使用向量也可以輕松得多。
首先,您包含了<string>
,但是您沒有使用<string>
必須提供的內容,即std::string
。 因為您說必須使用C樣式的字符串,所以正確的標頭是<cstring>
,而不是<string>
。
其次,如果傳遞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指針argumemts。 但是即使這樣,也存在傳遞未指向有效緩沖區的指針的風險。
現在,正如其他人所述,您需要正確地為每個具有指向動態分配的內存的指針的類編寫賦值運算符。
讓我們從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;
}
這不僅是多余的(大部分代碼在復制構造函數中),而且由於以下原因而失敗:
delete[]
名稱和姓氏。 如果以下new[]
引發異常會怎樣? 您已經通過刪除數據弄亂了對象,然后才能確保新的操作不會失敗。 修復方法很簡單,我建議您對所有其他類都這樣做。
#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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.