2016-04-18 2 views
0

Я получаю эту странную ошибку, которую я не смог выяснить. Я изучаю экзамен, поэтому я использую структуры вместо классов, потому что это то, что мы делали в классе. Вот мой кодC++ glibc double-free error

#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, тогда код работает нормально. Почему это? Я выделил память для каждого курса, поэтому я освобождаю эту память в деструкторе, поэтому я думаю, что программа не будет работать без нее, но это так. EDIT: Еще одна вещь. Это не имеет значения, когда я прокомментирую Студенту два = один; линия, так что я предполагаю, что ошибка в addCourse() и/или деструктор

Извините, что это такой длинный вопрос спасибо SO

+0

«поэтому я использую вместо структур классов» Вот немного C++ весело: Там нет 'struct's в C++. Я серьезно. 'struct' просто делает' class', где все является 'public', если не указано иначе. – user4581301

ответ

1

у вас есть проблемы в вашем операторе присваивания:

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]); 

вместо этого.

+0

Спасибо. Я изменю это –

0

В Student &operator=(const Student &s) вы копируете указатели на курсы от s, так что вы получаете двойное удаление.

Я считаю, что для целей вашей домашней работы вы можете просто сделать то же самое, что и в конструкторе копирования - создать новые курсы с одинаковыми именами.

+0

Я изменил свою функцию operator =(), но все еще получаю эту ошибку. Я думаю, что ошибка связана с конструктором копирования, так как это то, что вызывается, когда курсы добавляются –

1

Ваш оператор назначения неверен, о чем свидетельствуют другие ответы.

Однако, чтобы решить проблему легко, просто использовать 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); 

Live Example

или

Возьмите курсы по ссылке и скопируйте их (подобно тому, как работает 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); 

Live Example

+0

Спасибо. Однако я думаю, что проблема заключается в функции addCourse(). Когда я прокомментирую Студентку два = один; и two.print(); линии, я все еще получаю ошибку. Поэтому я предполагаю, что оператор-конструктор копирования и оператор присваивания не являются причиной этой ошибки. –

+0

Смотрите мои правки. Ваш класс предполагает, что все курсы были динамически распределены, когда они не являются. – PaulMcKenzie

+0

Спасибо. Оно работает. Просто для подтверждения удаление может быть вызвано только указателем, который был инициализирован новым, а не только любым указателем. Это правильно? –

Смежные вопросы