我撰寫了一個程式來創建一個鏈接串列,當我將串列的大小增加到一定程度并且關鍵地嘗試洗掉時,我得到了未定義的行為(或者我假設我這樣做了,因為程式剛剛停止而沒有任何錯誤)它(通過結束其范圍)。代碼的基本版本如下:
#include <iostream>
#include <memory>
template<typename T> struct Nodeptr;
template<class T>
struct Node {
Nodeptr<T> next;
T data;
Node(const T& data) : data(data) { }
};
template<class T>
struct Nodeptr : public std::shared_ptr<Node<T>> {
Nodeptr() : std::shared_ptr<Node<T>>(nullptr) { }
Nodeptr(const T& data) : std::shared_ptr<Node<T>>(new Node<T>(data)) { }
};
template<class T>
struct LinkedList {
Nodeptr<T> head;
void prepend(const T& data) {
auto new_head = Nodeptr<T>(data);
new_head->next = head;
head = new_head;
}
};
int main() {
int iterations = 10000;
{
LinkedList<float> ls;
std::cout << "START\n";
for(float k = 0.0f; k < iterations; k ) {
ls.prepend(k);
}
std::cout << "COMPLETE\n";
}
std::cout << "DONE\n";
return 0;
}
現在,當代碼運行時,會列印 START 和 COMPLETE,而不會列印 DONE。程式在沒有錯誤的情況下退出(出于某種原因)。當我將變數減小到 5000 而不是 10000 時,它作業得很好并且列印了 DONE。當我洗掉 LinkedList 宣告/測驗塊周圍的花括號時(將其從較小的范圍中取出,導致在列印 DONE 之前不會將其洗掉),然后一切正常并列印 DONE。因此,錯誤一定是由于洗掉程序而產生的,特別是由于被洗掉的東西的數量。但是,沒有錯誤訊息告訴我堆中沒有剩余空間,而且無論如何 10000 個浮點數似乎都很少填滿堆。任何幫助,將不勝感激!
解決了!它現在直接使用堆指標作業,并且我更改了 Node 的解構式以防止對其進行遞回呼叫:
~Node() {
if(!next) return;
Node* ptr = next;
Node* temp = nullptr;
while(ptr) {
temp = ptr->next;
ptr->next = nullptr;
delete ptr;
ptr = temp;
}
}
uj5u.com熱心網友回復:
它是由遞回解構式呼叫引起的堆疊溢位。
這是在撰寫任何深度嵌套的資料結構時應該注意的智能指標的常見問題。
您需要一個顯式的解構式,Node通過重置從串列尾部開始的智能指標來迭代地洗掉元素。還要遵循 3/5 規則,并對可能遞回破壞節點的所有其他操作執行相同的操作。
因為這本質上是重寫所有物件破壞,但是它首先使用智能指標有點值得懷疑,盡管在防止雙重洗掉(和泄漏)錯誤方面仍然有一些好處。因此,通常在這種情況下根本不使用智能指標,而是回退到資料結構節點的原始指標和手動生命周期管理。
此外,無論如何都不需要在std::shared_ptr這里使用。每個節點只有一個所有者。應該是std::unique_ptr。std::shared_ptr具有非常顯著的性能影響,并且如果形成回圈參考(無論是否有意),也存在可能導致泄漏的問題。
Nodeptr我也認為作為一個單獨的課程沒有任何意義。它似乎只是用作 的別名std::make_shared<Node>,可以通過使用函式來實作。特別是從標準庫智能指標繼承似乎是可疑的。如果有的話,我會改用組合。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/527280.html
上一篇:不兼容的整數到指標轉換從“int”分配給“int*”和分段錯誤錯誤(陣列和長度作為指標)
下一篇:函式內的malloc不改變指標值
