2012-10-08 29 views
3

在我的大學裏,有一個用C++進行的實際編程測試 - 而且我堅持一個例子,我不確定這個任務是否有效,正確完成。C++測試示例中可能存在的邏輯缺陷

的(簡單)的任務:

  • 完成的Person析構函數,使分配name再次

  • 釋放在主函數中,有需要的語句來替換//???釋放先前分配的內存

起初,這些任務對我而言似乎微不足道:對於析構函數,只需編寫delete[] name並在主函數中使用delete[] friends即可。據推測,這也是這個例子的作者意味着我們要做的。

然而:

似乎有在該代碼示例中的缺陷,這會導致內存泄漏以及析構函數被調用一次以上。

的人類沒有分配operator =,這意味着與現有的Person對象如maria被分配給時隙的主要功能的friends陣列中,內部分配name s的不被複制。因此,兩個對象現在共享相同的內部指針char*!此外,先前駐留在所述陣列插槽中的指向名稱Person的指針永久丟失,導致不可避免的內存泄漏。

As delete[] friends;被調用 - 數組中的對象被銷燬 - 導致它們的析構函數被調用並釋放它們的name成員。然而,當程序結束時,main範圍內的本地Person對象被破壞 - 當然,它們的name成員仍然指向之前已經釋放的內存。

實際的問題:

  • 這是測試例子有缺陷,還是我失去了一些東西?
  • 如果完全堅持執行給定的任務(只改變析構函數的實現,並在主函數的註釋部分插入新代碼),上面列出的問題是否可以解決?

..

#include <iostream> 
using namespace std; 

int strlen(const char *str) { 
    if (str==0) return 0; 
    int i=0; 
    for (; str[i]; ++i); 
    return i; 
} 

void strcpy(const char *src, char *dest) { 
    if (src==0 || dest==0) return; 
    int i=0; 
    for (; src[i]; ++i) dest[i]=src[i]; 
    dest[i]=’\0’; 
} 

class Person { 
    char *name; 
public: 
    Person(const char *str = "Susi") { 
     name = new char[strlen(str)+1]; 
     strcpy(str,name); 
    } 

    Person(const Person &p) { 
     name = new char[strlen(p.name)+1]; 
     strcpy(p.name,name); 
    } 

    ~Person() { 
     //... 
    } 

    void change() { 
     name[4]='e'; 
    } 

    ostream &print(ostream &o) const { 
     o<<name; 
     return o; 
    } 
}; 

int main() { 
    Person maria("Maria"), peter("Peter"), franz("Franz"), luisa("Luisa"); 
    Person mary(maria); 
    Person luise; 
    Person p(luise); 

    Person *friends= new Person[7]; 
    friends[0]=maria; 
    friends[1]=peter; 
    friends[2]=franz; 
    friends[3]=luisa; 
    friends[4]=mary; 
    friends[5]=luise; 
    friends[6]=p; 
    friends[5]=luisa; 
    friends[3].change(); 
    friends[4].change(); 

    for (int i=0; i<7; ++i) { 
    friends[i].print(cout); 
    cout<<endl; 
    } 

    //??? 
    return 0; 
} 
+7

你是對的。 [三項規則](http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29)被侵犯。 –

回答

5

你是絕對正確的。您可以僅使在指定位置的改變修復它,但他們都將是相當極端:

更換//...析構函數裏面有:

delete[] name; 
} 

Person& operator=(const Person& other) 
{ 
    if (this != &other) { 
     delete[] name; // not completely exception-safe! 
     name = new char[strlen(other.name)+1]; 
     strcpy(other.name,name); 
    } 
    return *this; 

另一個嚴重問題是重新定義標準函數(strcpy)和一個重新排列參數的新定義。

(參見:SQL注入攻擊,這也導致語法元素的現有對,經常引用和括號,以與插入的語法元素重新配對)

+0

你爲什麼要顯示異常不安全的方式? http://ideone.com/m09tB –

+0

@MooingDuck:你的修復也是不安全的 - 它只是吞下任何異常。正確的異常安全方法是使用'std :: vector'或'std :: string'來存放字符串數據。 –

+0

@ BenVoight:是的,我忘記了'catch;'catch塊的結尾處。 http://ideone.com/lZ0D2。你說得對,我會使用'std :: string',但這需要更多實質性的改變。 –

2
  1. 是,試驗例是有缺陷的,可能它是有意識地完成的。 Person類肯定需要賦值運算符,請記住Rule Of Three
  2. 不,這是不可能的。由編譯器生成的缺省賦值操作符會泄漏由friends數組中的對象分配的內存,並雙重刪除由auto Person對象分配的內存。
-1

對於每一個新的應該有一個刪除[]。

+0

對於每個'new'''delete',並且對於每個'new''''''''''''''。 –

+0

謝謝你的更正。 – awm