2013-04-20 112 views
0

我是C++的noob。我有一個我無法解決的問題。我寫了一個代碼,以瞭解更好的類和過載運算符:對象崩潰的破壞者

#include <iostream> 
#include <stdlib.h> 
#include <stdarg.h> 
using namespace std; 

class vectmy { 
public: 
    int size; 
int *a; 
vectmy(int n,int val); 
~vectmy(){delete[] a; //IF I DELETE THIS PROGRAM WORKS 
} 
vectmy & operator = (const vectmy &); 
}; 

vectmy::vectmy(int n,int val){ 
    size=n; 
    a = new int[ n+1 ]; 
    for (int i=0;i<n;++i){ 
    *(a+i)=val; 
    } 
} 



    vectmy& vectmy::operator= (const vectmy& param) 
    { 
    for (int i=0;i<3;++i) a[i]=param.a[i]; 
    return *this; 
    } 



vectmy operator+(vectmy left, vectmy right) 
    { 
    vectmy result = left; 
    for (int i=0;i<3;++i) result.a[i]=result.a[i]+right.a[i]; 

    return result; 
    } 



int main() { 
int b1[3]={1,2,4}; 
vectmy d(3,2),b(3,4),c(3,0); 

c=(b+d); 

for (int j=0; j<3; ++j)cout<<c.a[j]<<' '<<endl; 
return 0; 
} 

當我運行它崩潰。如果我刪除它的析構函數。爲什麼會發生?

+0

按照[三規則(http://en.wikipedia.org /維基/ Rule_of_three_%28C%2B%2B_programming%29)。你需要一個拷貝構造函數。 – juanchopanza 2013-04-20 11:30:06

+0

[三條法則是什麼?]可能重複(http://stackoverflow.com/questions/4172722/what-is-the-rule-of-reeree) – juanchopanza 2013-04-20 11:33:54

回答

2

當我運行它崩潰。如果我刪除它的析構函數。爲什麼會發生?

operator +創建複製left這裏的:

vectmy result = left; 

既然你沒有定義拷貝構造函數明確,編譯器會生成一個隱含執行成員明智複製。

a數據部件的沉悶拷貝意味着該a指針將最終指向相同位置的vectmyresultleft)兩個不同的實例,兩者delete[]它在破壞。

這樣的雙刪除給你的程序未定義的行爲,在你的情況下,它表現爲崩潰。

這是對Rule of Three點:每次有一個用戶定義的拷貝構造函數,賦值運算符或析構函數的時候,你應該定義他們的所有

原因是你通常會定義其中的一個函數,因爲你正在管理一些資源(在你的情況下是內存),並且你通常要在複製,銷燬或分配管理資源的對象時執行適當的操作。

在這種特殊情況下,缺少正確的拷貝構造函數。這是你能怎麼定義它:

vectmy::vectmy(vectmy const& v) 
{ 
    size=v.size; 
    a = new int[size]; 
    *this = v; 
} 

另外,我建議你通過原始指針,newdelete(或他們的陣列同行),以避免手動內存管理,只要你能,並考慮使用std::vector代替。

UPDATE:

還要注意,您operator +由值接受其參數,這意味着每一個參數將被複制(即,拷貝構造將被調用)。

由於副本是不是真的有必要在這裏,您可能希望通過引用(至const)把你的參數:

vectmy operator + (vectmy const& left, vectmy const& right) 
//       ^^^^^^    ^^^^^^ 
+0

非常好的答案,非常感謝!當然我會使用std :: vector,它只是一個測試,看看如何使用指針數據成員的類表現行爲。 – 2013-04-20 11:43:42

+0

但是我試着用這個運算符insted:'vectmy vectmy :: operator +(const vectmy param) { \t vectmy temp(3,0); \t for(int i = 0; i <3; ++ i)temp.a [i] = a [i] + param.a [i]; \t return temp; '我發現它可以和你的副本構造函數一起工作,但不是沒有,儘管temp是創建的而不是被另一個複製的!你能否澄清這一點?謝謝! – 2013-04-20 12:03:05

+0

@TommasoFerrari:很高興幫助:)原因是你的'operator +'通過value *接受它的參數*,當通過值傳遞參數時,創建一個副本 - 這意味着複製構造函數被調用。這就是爲什麼它只在你定義一個合適的拷貝構造函數時才起作用。但是,您不需要在這裏按值接受您的參數 - 您不需要'operator +'參數的副本。我擴大了我的答案了一下。 – 2013-04-20 12:14:03

1

在你operator+你做

vectmy result = left; 

這將調用默認的構造函數拷貝構造函數,而你沒有。因此將使用編譯器變體,它不會爲a成員分配內存。對於自動生成的拷貝構造函數,指針將被簡單地複製,使得兩個對象使用相同的指針。當刪除它時,另一個指針變爲無效。

您應該閱讀約the rule of three