2016-04-18 22 views
0

私が把握できなかったこの奇妙なエラーが発生しています。私は試験のために勉強しているので、クラスの代わりに構造体を使用しています。これは、クラスで行ったことだからです。ここに私のコードはC++ glibc double-freeエラー

#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デストラクタをコメントアウトすると、コードは正常に動作します。何故ですか?私は各コースのためにメモリを割り当てたので、私はデストラクタでそのメモリを解放していますので、プログラムはそれなしでは動作しないと思うでしょうが、そうします。 編集:もう1つ。それは私が学生2 = 1をコメントアウトするときに違いはありません。ラインので、私はこれがあなたの代入演算子に問題がある どうもありがとうSO

+0

「私が代わりにクラスの構造体を使用しています」ここでC++の楽しみのビットがあります:C++には 'struct'sはありません。私は真剣です。 'struct'は他に宣言されていない限り' public'である 'class'を作成します。 – user4581301

答えて

1

ような長い質問であるというエラーが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; 
    } 

あなたは生のポインタではないオブジェクトをコピーして、第二Student同じCourseのデストラクタに二度目を破壊したように、その後、2つの別々の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()関数にあると思います。私が学生2 = 1をコメントアウトすると、 and two.print();私はまだエラーが発生します。だから私はコピーコンストラクタadn代入演算子がここでエラーを引き起こしていないと推測している。 –

+0

私の編集を参照してください。あなたのクラスは、すべてのコースが動的に割り当てられていないときにそれが割り当てられているとみなします。 – PaulMcKenzie

+0

ありがとうございます。できます。確認するだけで、deleteは新しいポインタではなく新しいポインタで初期化されたポインタに対してのみ呼び出すことができます。そうですか? –