我有一個例子,我有一個類在建構式中分配記憶體,并在解構式中釋放它——非常基本的東西。如果我將類實體變數重用于類的新實體,就會出現問題。當最終的(并且只有最終的)實體在超出范圍時被銷毀時,它將在呼叫 free/delete 時崩潰并出現 SIGABRT:
malloc: *** error for object 0xXXXXX: pointer being freed was not allocated
我覺得我錯過了一些基本的東西,我想了解我的錯誤,以便將來避免它。
這是一個簡單的復制:
class AllocTest {
public:
AllocTest(const char *c) {
this->data = new char[strlen(c) 1];
strcpy(this->data, c);
}
~AllocTest() {
if (this->data != NULL) {
delete[] data;
}
}
private:
char* data;
};
int main(int argc, const char *argv[]) {
const char* c = "test test test";
AllocTest t(c);
t = AllocTest(c);
t = AllocTest(c);
return 0;
}
我可以在除錯器中看到每次呼叫的解構式t都會根據前一個實體重新分配,為什么只有最終的解構式會導致崩潰?我是否使用new/delete或malloc/都沒關系free——無論哪種方式都是相同的行為——并且僅在最終釋放時。如果我移動范圍或其他任何東西也沒關系 - 一旦最終范圍離開,就會發生崩潰。
如果將變數 't' 限制在它自己的范圍內并且不嘗試重用它,這不會重現 - 例如,如果我這樣做,一切都很好:
for (int i = 0; i < 100; i ) {
AllocTest t(c);
}
解決這個問題很簡單,但我更愿意理解為什么我會遇到這個問題。
UPDATE:
Thanks to the answer from @user17732522, I now understand what the problem is here. I didn't realize that when I was reassigning t that it was actually making a copy of the class -- I was working on an assumption that like other languages that I typically work with that the assignment overwrites it. Upon realizing this things all made sense as I was unwittingly stumbling into a classic "double free" problem. The documentation on copy initialization and the pointers to the documentation about the rule of three pattern helped fill in the rest of the gaps here.
Simply modifying my class to define the implicit copy semantic was enough to cause the code to work as expected:
AllocTest& operator=(const AllocTest& t) {
if (this == &t) {
return *this;
}
size_t newDataLen = strlen(t.data) 1;
char* newData = new char[newDataLen];
strcpy(newData, t.data);
delete this->data;
this->data = newData;
return *this;
}
Thanks, folks!
uj5u.com熱心網友回復:
首先,建構式本身具有未定義的行為,因為您只為字串 ( ) 的長度分配了足夠的空間,而字串 ( strlen(c)) 缺少空終止符所需的附加元素。
假設您在下面解決了這個問題。
物件/實體上的解構式只被呼叫一次。
在您的代碼t中始終是相同的實體。它永遠不會被新的取代。您只是分配給它,它使用隱式復制分配運算子將臨時物件中t的成員一一復制分配給 的成員。
解構式 ont只被呼叫一次,當它的作用域在return陳述句之后結束時。
這個解構式呼叫具有未定義的行為,因為最后一個AllocTest(c)臨時物件的解構式已經洗掉了t.data此時指向的已分配陣列(它已經用 分配了該值t = AllocTest(c);)。此外,第一個分配AllocTest t(c);已經泄露,因為你t.data用 first 覆寫了指標t = AllocTest(c);。
只是AllocTest t(c);你沒有復制任何指標,所以這不會發生。
這里的根本問題是你的類違反了0/3/5 的規則:如果你有一個解構式,你還應該用正確的語意定義復制/移動建構式和賦值運算子。如果您需要自定義解構式,隱含的(您在此處使用的)可能會做錯事。
或者更好的是,通過不手動分配記憶體來實作零規則。使用std::string它,您不必定義解構式或任何特殊的成員函式。這也自動解決了長度不匹配的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438345.html
下一篇:在C 中使用函式引數定義結構方法
