2014-06-09 14 views
0

對於Accelerated C++練習,我正在實現一個名爲Str的自定義字符串類。當底層存儲容器是一個自定義矢量(Vec)時,一切正常,但現在我遇到了一個奇怪的情境問題,我不明白。顯式調用非默認ctor時覆蓋自定義字符串失敗

如果我通過顯式調用像Str newStr("some words");的構造函數,然後創建一個新的Str對象試圖覆蓋使用它cin >> newStr;程序崩潰到底,給在調試器SIGABRT當它達到Str析構函數(這僅僅是delete[] data; )。

如果我創建一個新的空Str然後用cin來填補它像Str newStr; cin >> newStr;,或者如果我使用cin覆蓋我做了使用Str newStr = "some words";一個Str這不會發生,當我嘗試重寫Str它只是失敗通過顯式調用非默認構造函數來實現,即使此類型在被覆蓋之前正確顯示。

在這種情況下,另一個奇怪的事情,如果我只是不創建創建/顯示奇數行爲Str和使用cin改變其價值之間的任何新Str 5事實上正常工作。

Str a = "Here is a"; 
Str b("And here is b"); 

cout << a << endl << b << endl; 

Str c = "Finally we have c"; 
cout << c << endl; 
cin >> c; 
cout << c << endl << endl; 

cin >> b; 
cout << b << endl; 

這說明你,你可以覆蓋Str c成功,但是當你試圖覆蓋Str b崩潰。然而,這可以讓你覆蓋b和程序成功完成:

Str a = "Here is a"; 
Str b("And here is b"); 

cout << a << endl << b << endl; 

cin >> b; 
cout << b << endl; 

Str包含被同時用於ab私有成員char* dataint length, limit和構造是:

Str::Str(const char* cp) { 
    limit = length = std::strlen(cp); 
    data = new char[length]; 
    for (size_type i = 0; i != length; ++i) 
     data[i] = cp[i]; 
} 

我也有>>好友及其實施是:

istream& operator>>(istream& is, Str& s) { 
    delete[] s.data; 
    s.length = s.limit = 0; 

    char c; 
    while (is.get(c) && isspace(c)) ; 

    if (is) { 
     do s.push_back(c); 
     while (is.get(c) && !isspace(c)); 

     if (is) 
      is.unget(); 
    } 
    return is; 
} 

我知道push_back可能是一個奇怪的功能在這個類中,但它工作正常,即使使用cin很長的Str需要許多push_back。我試着調整/類的不同部分經營者幾個小時,很爲難O_O

最後,我不知道爲什麼我的副本構造函數不會被調用過程中使用Str newStr = "blah";Str初始化(與cout小號選中)語法,即使它有效。

編輯,的push_back:

void Str::push_back(char c) { 
    if (length == limit) { 
     limit = std::max(limit*2, 1); 
     char* newData = new char[limit]; 

     for (size_type i = 0; i < length; ++i) 
      newData[i] = data[i]; 

     delete[] data; 
     data = newData; 
    } 
    data[length++] = c; 
} 
+0

當你使用一個潛在的'的std :: VECTOR' ''push_back()'函數是內置的。現在你正在使用一個字符緩衝區,你必須編寫你自己的'push_back()'。看起來很可能這是錯誤所在。請在這裏發佈信息。 –

+0

當使用'Vec'時,我還必須編寫'push_back()',因爲這個練習涉及到讓一個自定義類像'std :: vector'一樣編輯來顯示我的'Str :: push_back()',似乎在其他情況下工作,當它被稱爲多次覆蓋像'str someStr =「asdf」;' – Instinct

+1

沒有什麼明顯錯誤。如果可以發佈整個源代碼,我會把它放在調試器中,看看會發生什麼。 –

回答

2

delete[]輸入運算符的內存時,需要確保data成員設置爲0。如果你不這樣做,你會delete[]這已經delete[] d在push_back()和你的程序的非空指針將有不確定的操作:

istream& operator>>(istream& is, Str& s) { 
    delete[] s.data; 
    s.data = 0; // needed to keep your class invariants correct 
    s.length = s.limit = 0; 
    // ... 
} 
+0

啊哈沒有聽到!這就是說,這意味着在調用push_back()之前以'push_back()'方式刪除了內存(它將會有一個未知,不同的目的)? – Instinct

+1

@Instinc:no。在delete [] s.data後面,成員s.data清楚地包含了一個指向'delete []'d內存的指針。然後在你的'push_back()'中,你會分配新的內存並調用'delete [] s.data',它將嘗試'delete'已經'delete []'的指針,從而導致未定義的行爲。它可能會損壞內存管理系統中的某些東西)。 –

+0

有道理,感謝您的幫助! – Instinct

0

的構造不是爲終止空字符分配空間(並且不將其存儲任一)。

我有一種感覺,將其更改爲:

Str::Str(const char* cp) { 
    limit = length = std::strlen(cp); 
    data = new char[length+1]; 
    for (size_t i = 0; i != length; ++i) 
     data[i] = cp[i]; 
    data[length] = '\0'; 
} 

將解決您的問題。

雖然在此我將建議稍微改變push_back,以便它總是添加終止的空字符。

void Str::push_back(char c) { 
    if (length == limit) { 
     limit = (limit > 0 ? limit*2 : 1); 
     char* newData = new char[limit+1]; 

     for (size_t i = 0; i < length; ++i) 
      newData[i] = data[i]; 

     delete[] data; 
     data = newData; 
    } 
    data[length++] = c; 
    data[length] = '\0'; 
} 

更新

通過@Dietmar答案是一個關鍵補丁。不確定這是否是你需要的。

+0

即使發生這種變化,它仍然崩潰,即使沒有其他代碼檢查它,我是否還需要終止空值? – Instinct

+0

嘗試更新'push_back'並查看是否有任何區別。 –

+0

在兩個函數中複製,由於某種原因仍然相同 – Instinct

相關問題