簡體   English   中英

了解鏗鏘有力的“DeadStores”和“NewDeleteLeaks”警告

[英]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
}

現在,我有兩個問題。

  1. 我意識到上面標記的 L52 不起作用。 例如,如果我執行TreeNode* node = new TreeNode(5); TreeNode* empty = NULL; insert(empty, node); TreeNode* node = new TreeNode(5); TreeNode* empty = NULL; insert(empty, node); ,它不會工作。 我不知道如何解決這個問題,所以任何幫助都會很棒。

  2. 在我的代碼上運行 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)導致了這個問題。 有什么更好的方法來實現我想要的? 我可以閱讀的任何進一步的解釋或資源都會很棒。

當然,對我糟糕的編碼風格的任何改進都會很棒;)格式化程序可以節省一天的時間。

謝謝!

Q1:如何插入二叉樹?

片段的主要問題:

void insert(TreeNode* root, TreeNode* v) {
  // inserts v into root, assuming values distinct
  if (root == NULL) {
    root = v; // L52
    return;
  }

也就是說,盡管您為root設置了新值,但rootinsert函數的參數,因此在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的新值指向包含插入值的樹。

Q2:clang-tidy 在抱怨什么?

調用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

關於智能指針的說明

我上面的建議使用了一種非常直接的、字面意義上的內存管理方式,在需要的地方顯式地使用了newdelete 但是,很容易忘記使用delete ,並且在出現異常時很難正確使用它。 通常首選的替代方法是使用智能指針 但這是一個有點高級的話題,所以剛開始時,我建議先熟悉顯式newdelete ,但請記住,當你准備好時,還有更好的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM