Я получаю эту странную ошибку, которую я не смог понять. Я готовлюсь к экзамену, поэтому я использую структуры вместо классов, потому что это то, что мы делали в классе. Вот мой код
#include <iostream>
#include <string>
using namespace std;struct Course;
ostream &operator<<(ostream &os, Course c);struct Course {
string name;
Course(string n) {
name = n;
}
Course(const Course &c) {
cout << "Copying course" << endl;
name = c.name;
}
Course &operator=(const Course &c) {
cout << "Assigning course" << endl;
name = c.name;
return *this;
}
};struct Student {
int id;
Course *courses[5];
int size;
Student(int num) {
id = num;
for (int i = 0; i < 5; i++) {
courses[i] = new Course("Course");
}
size = 0;
}
Student(const Student &s) {
cout << "Copying student" << endl;
id = s.id;
for (int i = 0; i < 5; i++) {
Course *temp = new Course(s.courses[i]->name);
courses[i] = temp;
}
}
Student &operator=(const Student &s) {
cout << "Assigning student" << endl;
id = s.id;
for (int i = 0; i < 5; i++) {
courses[i] = s.courses[i];
}
return *this;
}
~Student() {
for (int i = 0; i < 5; i++) {
delete courses[i];
}
}
void print() {
cout << id << ": " << endl;
for (int i = 0; i < 5; i++) {
cout << courses[i]->name << endl;
}
}
void addCourse(Course *c) {
delete courses[size];
courses[size] = c;
size++;
}
};
ostream &operator<<(ostream &os, Course *c) {
return os << c->name << endl;
}
int main() {
Student one(2342134);
Course cs246("cs246");
Course cs245("cs245");
one.addCourse(&cs246);
one.addCourse(&cs245);
one.print();
Student two = one;
two.print();
}
Вот ошибка
2342134:
cs246
cs245
Course
Course
Course
Copying student
2342134:
cs246
cs245
Course
Course
Course
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000000cd8db0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7db26)[0x7f359a7ddb26]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x40)[0x7f359adf87c0]
./a.out[0x40111e]
./a.out[0x401152]
./a.out[0x400dc7]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f359a78176d]
./a.out[0x400b89]
======= Memory map: ========
00400000-00402000 r-xp 00000000 00:34 45960378 /u3/z38ahmed/cs246/1161/exam/2.22_Object/2.22.5_Copy-Constructor-and-Assignment/a.out
00601000-00602000 r--p 00001000 00:34 45960378 /u3/z38ahmed/cs246/1161/exam/2.22_Object/2.22.5_Copy-Constructor-and-Assignment/a.out
00602000-00603000 rw-p 00002000 00:34 45960378 /u3/z38ahmed/cs246/1161/exam/2.22_Object/2.22.5_Copy-Constructor-and-Assignment/a.out
00cc7000-00cf9000 rw-p 00000000 00:00 0 [heap]
7f359a460000-7f359a55b000 r-xp 00000000 fc:00 915519 /lib/x86_64-linux-gnu/libm-2.15.so
7f359a55b000-7f359a75a000 ---p 000fb000 fc:00 915519 /lib/x86_64-linux-gnu/libm-2.15.so
7f359a75a000-7f359a75b000 r--p 000fa000 fc:00 915519 /lib/x86_64-linux-gnu/libm-2.15.so
7f359a75b000-7f359a75c000 rw-p 000fb000 fc:00 915519 /lib/x86_64-linux-gnu/libm-2.15.so
7f359a760000-7f359a914000 r-xp 00000000 fc:00 915563 /lib/x86_64-linux-gnu/libc-2.15.so
7f359a914000-7f359ab13000 ---p 001b4000 fc:00 915563 /lib/x86_64-linux-gnu/libc-2.15.so
7f359ab13000-7f359ab17000 r--p 001b3000 fc:00 915563 /lib/x86_64-linux-gnu/libc-2.15.so
7f359ab17000-7f359ab19000 rw-p 001b7000 fc:00 915563 /lib/x86_64-linux-gnu/libc-2.15.so
7f359ab19000-7f359ab1e000 rw-p 00000000 00:00 0
7f359ab20000-7f359ab36000 r-xp 00000000 fc:00 914560 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f359ab36000-7f359ad35000 ---p 00016000 fc:00 914560 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f359ad35000-7f359ad36000 r--p 00015000 fc:00 914560 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f359ad36000-7f359ad37000 rw-p 00016000 fc:00 914560 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f359ad38000-7f359ae3a000 r-xp 00000000 fc:00 396701 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f359ae3a000-7f359b039000 ---p 00102000 fc:00 396701 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f359b039000-7f359b041000 r--p 00101000 fc:00 396701 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f359b041000-7f359b043000 rw-p 00109000 fc:00 396701 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f359b043000-7f359b046000 rw-p 00000000 00:00 0
7f359b048000-7f359b06a000 r-xp 00000000 fc:00 915535 /lib/x86_64-linux-gnu/ld-2.15.so
7f359b268000-7f359b26a000 rw-p 00000000 00:00 0
7f359b26a000-7f359b26b000 r--p 00022000 fc:00 915535 /lib/x86_64-linux-gnu/ld-2.15.so
7f359b26b000-7f359b26d000 rw-p 00023000 fc:00 915535 /lib/x86_64-linux-gnu/ld-2.15.so
7f359b26d000-7f359b274000 rw-p 00000000 00:00 0
7ffdfdac4000-7ffdfdae5000 rw-p 00000000 00:00 0 [stack]
7ffdfdb78000-7ffdfdb7a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted
Я не знаю, что означает glibc, но я не вижу, где я освобождаюсь дважды. Когда я комментирую деструктор Student, то код работает нормально. Это почему? Я выделил память для каждого курса, поэтому я освобождаю эту память в деструкторе, поэтому я думаю, что программа не будет работать без нее, но это работает.
РЕДАКТИРОВАТЬ: еще одна вещь. Это не имеет значения, когда я комментирую Студента два = один; строка, так что я предполагаю, что ошибка в addCourse () и / или деструкторе
Извините, что это такой длинный вопрос
Большое спасибо ТАК
У вас есть проблема в вашем операторе присваивания:
Student &operator=(const Student &s) {
cout << "Assigning student" << endl;
id = s.id;
for (int i = 0; i < 5; i++) {
courses[i] = s.courses[i];
}
return *this;
}
вы копируете сырые указатели, а не объекты, а затем 2 отдельных Student
объекты владеют одним и тем же Course
те, так что деструктор второй Student
так же Course
разрушен во второй раз. Вероятно, вы хотели:
*(courses[i]) = *(s.courses[i]);
вместо.
Ваш оператор присваивания неверен, как указано в других ответах.
Однако, чтобы решить вашу проблему легко, просто используйте copy / swap
, поскольку вы уже закодировали конструктор копирования и деструктор для своего класса:
#include <algorithm>
//...
Student &operator=(const Student &s)
{
cout << "Assigning student" << endl;
Student temp(s);
std::swap(temp.id, id);
std::swap(temp.courses, courses);
return *this;
}
Мы только что создали временный Student
копия с переданного Student
, а затем обменялись внутренними членами текущего студента с временными. Опять же, это может работать только с конструктором и деструктором рабочей копии для Student
(который вы уже предоставили).
Другая проблема заключается в addCourse
функция. Проблема в том, что вы указываете на объекты, которые были не динамически распределяется. Когда вызывается деструктор, предполагается, что все указатели были получены из вызова new
, когда они этого не сделали.
void addCourse(Course *c) {
delete courses[size];
courses[size] = c;
size++;
}
~Student() {
for (int i = 0; i < 5; i++) {
delete courses[i]; // <-- Assumes all courses were allocated dynamically
}
}
//...
Course cs246("cs246");
Course cs245("cs245");
one.addCourse(&cs246); // <-- Not allocated with new
one.addCourse(&cs245); // <-- Not allocated with new
Это недостаток вашего дизайна. Либо запретить это, крича на main
не делай этого, я беру только вещи, выделенные new
«, и иметь этот код:
Course* cs246 = new Course("cs246");
Course* cs245 = new Course("cs245");
one.addCourse(cs246);
one.addCourse(cs245);
или же
Возьмите курсы по ссылке и скопируйте их (аналогично тому, как vector
работает) и управляй памятью сам в классе.
void addCourse(const Course& c)
{
delete courses[size];
Course* temp = new Course(c);
courses[size] = temp;
size++;
}
//...
Course cs246("cs246");
Course cs245("cs245");
one.addCourse(cs246);
one.addCourse(cs245);
В Student &operator=(const Student &s)
вы копируете указатели на курсы из s
, так что вы получите двойное удаление.
Я считаю, что для целей вашей домашней работы вы можете сделать то же самое, что и в конструкторе копирования — создать новые курсы с такими же именами.