[英]Understanding clang-tidy "DeadStores" and "NewDeleteLeaks" warnings
我對 c++ 編程比較陌生,尤其是在處理 OOP 和指針時。
我正在嘗試實現二叉搜索樹,這是我擁有的代碼
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode() : val(0), left(NULL), right(NULL){};
TreeNode(int v) : val(v), left(NULL), right(NULL){};
TreeNode(int v, TreeNode* l, TreeNode* r) : val(v), left(l), right(r){};
};
void insert(TreeNode* root, TreeNode* v) {
// inserts v into root, assuming values distinct
if (root == NULL) {
root = v; // L52
return;
}
if (v == NULL) {
return;
}
// traverse through tree using structure of BST
TreeNode* cur = root;
while (cur != NULL) {
if (cur->val <= v->val) {
if (cur->right == NULL) {
cur->right = new TreeNode(v->val);
break;
}
cur = cur->right;
} else if (cur->val >= v->val) {
if (cur->left == NULL) {
cur->left = new TreeNode(v->val);
break;
}
cur = cur->left;
}
}
}
void insert(TreeNode* root, int v) {
insert(root, new TreeNode(v)); // L78
}
現在,我有兩個問題。
我意識到上面標記的 L52 不起作用。 例如,如果我執行TreeNode* node = new TreeNode(5); TreeNode* empty = NULL; insert(empty, node);
TreeNode* node = new TreeNode(5); TreeNode* empty = NULL; insert(empty, node);
,它不會工作。 我不知道如何解決這個問題,所以任何幫助都會很棒。
在我的代碼上運行 clang-tidy,我得到以下稍微令人困惑的警告:
./main.cpp:78:69: warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
void insert(TreeNode* root, int v) { insert(root, new TreeNode(v)); }
^
./main.cpp:132:3: note: Calling 'insert'
insert(node, 3);
^
./main.cpp:78:51: note: Memory is allocated
void insert(TreeNode* root, int v) { insert(root, new TreeNode(v)); }
^
./main.cpp:78:69: note: Potential memory leak
void insert(TreeNode* root, int v) { insert(root, new TreeNode(v)); }
^
我不確定這意味着什么,以及它是否會以任何方式危險。 我從 LLVM 文檔中找到了這個,似乎臨時的new TreeNode(v)
導致了這個問題。 有什么更好的方法來實現我想要的? 我可以閱讀的任何進一步的解釋或資源都會很棒。
當然,對我糟糕的編碼風格的任何改進都會很棒;)格式化程序可以節省一天的時間。
謝謝!
片段的主要問題:
void insert(TreeNode* root, TreeNode* v) {
// inserts v into root, assuming values distinct
if (root == NULL) {
root = v; // L52
return;
}
也就是說,盡管您為root
設置了新值,但root
是insert
函數的參數,因此在insert
返回時被丟棄。
解決此問題的一種方法是返回新值:
TreeNode* // <-- changed return type
insert(TreeNode* root, TreeNode* v) {
// inserts v into root, assuming values distinct
if (root == NULL) {
root = v; // L52
return root; // <---- changed to return a value
}
每個地方insert
返回(包括在末尾),返回root
的值。
然后當你調用insert
時,保存返回值:
TreeNode* root = ...; // some existing tree
root = insert(root, 5); // insert 5 and save the result
現在, root
的新值指向包含插入值的樹。
調用new
分配內存。 它最終必須被釋放,否則(如果這種情況繼續發生)您的程序最終將使用所有可用內存。 請參閱問題何時應該在 C++ 中使用 new 關鍵字? . 請特別注意以下建議:“每次鍵入new
時,鍵入delete
。”
現在,在這段代碼中,問題實際上不是缺少delete
,而是未能返回更新后的root
。 clang-tidy
意識到,因為更新的root
永遠不會返回,你不可能最終delete
它,所以抱怨。 一旦你開始返回那個值, clang-tidy
就會等着看你下一步做什么。
至於接下來要做什么,一種簡單的方法是將TreeNode
視為擁有其子節點,這意味着它必須在銷毀時將其delete
。 例如,首先給TreeNode
添加一個析構方法:
struct TreeNode {
...
~TreeNode() { // <--- this is the destructor
delete left; // free left child (if not NULL)
delete right; // free right child
}
};
然后在操作樹的代碼中,記得在完成后delete
根節點:
TreeNode* root = NULL;
root = insert(root, 1);
root = insert(root, 2);
delete root; // <--- free entire tree
我上面的建議使用了一種非常直接的、字面意義上的內存管理方式,在需要的地方顯式地使用了new
和delete
。 但是,很容易忘記使用delete
,並且在出現異常時很難正確使用它。 通常首選的替代方法是使用智能指針。 但這是一個有點高級的話題,所以剛開始時,我建議先熟悉顯式new
和delete
,但請記住,當你准備好時,還有更好的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.