c++双精度释放或损坏(out):即使使用复制构造函数和赋值操作符
C++ double free or corruption (out): Even with copy constructor and assignment operator
我的代码正在生成*错误在' ./a。out': double free or corruption (out): 0x00007ffe400eb0e0 *
每当它运行时,我假设这是一个基于我的复制构造函数或如何删除我的动态数组的问题,但我有麻烦找出问题出现的地方:
我的类:
class Student {
public:
Student();
Student(const Student&);
Student & operator= (const Student&);
~Student();
void setStudentData(int *, int &, int, string);
int getNumOfSubjTaken();
int getAverageMark();
int getLowestMark();
int getHighestMark();
string getFullName();
void sortMarks(int &);
private:
string fullName;
int *marks;
int numOfSubjects;
};
拷贝构造函数:
Student::Student(const Student& pupil) {
marks = new int[numOfSubjects = pupil.numOfSubjects];
for (int i = 0; i < numOfSubjects; i++) {
marks[i] = pupil.marks[i];
}
fullName = pupil.fullName;
//removed after edit: marks = pupil.marks;
}
赋值运算符:
Student &Student::operator=(const Student &pupil) {
if (this != &pupil) {
for (int i = 0; i < numOfSubjects; i++) {
marks[i] = pupil.marks[i];
}
fullName = pupil.fullName;
numOfSubjects = pupil.numOfSubjects;
marks = pupil.marks;
}
return *this;
}
拆解:
Student::~Student(){
if (marks != NULL) {
delete [] marks;
}
marks = NULL;
numOfSubjects = 0;
fullName = "";
}
Set Function (Mutator):
void Student::setStudentData(int *markArray, int &numStudents, int numSub, string fullName) {
marks = new int[numSub];
for (int i = 0; i < numSub; i++) {
marks[i] = markArray[i];
}
this->numOfSubjects = numSub;
this->fullName = fullName;
}
只有在我实现了我的写函数之后,这个问题才发生:
void writeFile(fstream &fout, char *argv[], Student *pupil, int &numRecs) {
const char sep = ' ';
const int nameWidth = 5;
const int numWidth = 7;
fout.open(argv[2]);
if (!fout.good()) {
cout << "Error: Invalid data in " << argv[1] << " file." << endl;
cout << "The program is terminated.";
exit(EXIT_FAILURE);
}
else {
// creating the table output
fout << left << setw(nameWidth) << setfill(sep) << "Full Name";
fout << left << setw(numWidth) << setfill(sep) << "mark1";
fout << left << setw(numWidth) << setfill(sep) << "mark2";
fout << left << setw(numWidth) << setfill(sep) << "mark3";
fout << left << setw(numWidth) << setfill(sep) << "mark4";
fout << left << setw(numWidth) << setfill(sep) << "average";
fout << left << setw(numWidth) << setfill(sep) << "min";
fout << left << setw(numWidth) << setfill(sep) << "max";
fout << endl;
for (int i = 0; i < numRecs; i++) { //numRecs being number of records/students
fout << left << setw(nameWidth) << setfill(sep) << pupil[i].getFullName();
for (int j = 0; j < pupil[i].getNumOfSubjTaken(); j++) { //writes each mark up to
//fout << left << setw(numWidth) << setfill(sep) << pupil[i].marks[j];
//This line doesn't work, but i need to be able to write the marks.
}
if (pupil[i].getNumOfSubjTaken() < 4) {
for (int k = pupil[i].getNumOfSubjTaken(); k != 4; k++) {
fout << left << setw(numWidth) << setfill(sep) << " ";
}
}
fout << left << setw(numWidth) << setfill(sep) << pupil[i].getAverageMark();
fout << left << setw(numWidth) << setfill(sep) << pupil[i].getLowestMark();
fout << left << setw(numWidth) << setfill(sep) << pupil[i].getHighestMark();
fout << endl;
}
}
}
我似乎也无法自拔<<学生[我].marks [j];即使它应该工作。
感谢您的时间和帮助。
您的赋值操作符是不正确的,因为它只做marks
指针的浅拷贝。因此,您将得到一个双重自由错误,因为两个对象(this
和pupil
)中的marks
指针在对这些对象调用析构函数时将指向相同的内存。
注意,如果你使用std::vector<int> marks;
而不是int *marks;
,那么就不需要复制构造函数、赋值操作符或析构函数,因为std::vector<int>
基本上完成了你在复制构造函数、赋值操作符和析构函数中试图做的事情。不同之处在于std::vector<int>
安全、高效、无错误地完成了这一操作。
话虽如此,对代码的修复(不是唯一可能的修复)将是分配与传入的Student
对象的主题数量匹配的新内存,释放marks
内存,然后将marks
分配给带有复制数据的新分配的内存。
Student &Student::operator=(const Student &pupil)
{
if (this != &pupil)
{
// allocate new memory and copy
int *temp = new int [pupil.numOfSubjects];
for (int i = 0; i < pupil.numOfSubjects; i++)
temp[i] = pupil.marks[i];
// deallocate old memory and assign
delete [] marks;
marks = temp;
fullName = pupil.fullName;
numOfSubjects = pupil.numOfSubjects;
}
return *this;
}
作为上述代码的替代,因为您似乎有一个工作的复制构造函数和析构函数(以下代码正确工作所必需的),一个更简单的解决方案是使用复制/交换习惯用法。
#include <algorithm>
//...
Student &Student::operator=(const Student &pupil)
{
Student temp(pupil);
std::swap(temp.numOfSubjects, numOfSubjects);
std::swap(temp.marks, marks);
std::swap(temp.fullName, fullName);
return *this;
}
使用复制构造函数和析构函数创建临时对象,然后用临时对象的内部结构替换this
的内部结构。然后临时对象就会随着旧的内部结构一起消亡。
如果您想要一个可以调整大小的数组,STL已经提供了一个。您可以使用std::vector<int>
来代替自己操作内存。
我读了你的复制构造函数,它似乎很好。同时,我认为你还应该创建一个move构造函数。
在你的赋值操作符中:
for (int i = 0; i < numOfSubjects; i++) {
marks[i] = pupil.marks[i];
}
fullName =小学生.fullName;nummofsubjects = student . nummofsubjects;
- 你没有分配
this->mark
。如果pupil.marks
和this->marks
的大小不一样呢? - 循环不能复制
pupil.marks
的全部内容,只能复制this->marks
所能容纳的部分。 - 你把东西复制到
this->marks
(这很好,一个深拷贝),但然后你做marks = pupil.marks
。- 深拷贝变为冗余
- 它使
this
和pupil
"拥有"相同的marks
,这意味着两者都会尝试在析构函数中释放它,导致你的问题。 - 这一行引入了内存泄漏。
在析构函数中:
if (marks != NULL) {
delete [] marks;
}
marks = NULL;
numOfSubjects = 0;
fullName = "";
- 比较指针到
NULL
是一种C的做事方式。它基本上是一个通常等于0的宏。比较nullptr
更正确。 - 没有必要设置
marks
为nullptr
后,你已经释放了它。分配给其他成员也没有意义。
在您的肉函数:
for (int i = 0; i < numRecs; i++) {
//numRecs being number of records/students
fout << left << setw(nameWidth) << setfill(sep) << pupil[i].getFullName();
for (int j = 0; j < pupil[i].getNumOfSubjTaken(); j++) {
fout << left << setw(numWidth) << setfill(sep) << pupil[i].marks[j];
}
}
- 如果
numRecs
大于pupil
数组的大小,则会出现溢出
所有这些点都是bug产生的原因。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用