为什么内存泄漏?

Why memory leak?

我第一次在clang中尝试LeakSanitizer。我将 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak -g") 添加到我的 CMakeLists.txt.

这是我的 main.cpp

#include <iostream>
#include "linked_queue.h"

int main() {
    linked::Char_queue charQueue;
    charQueue.enqueue('1');
    charQueue.enqueue('2');
    charQueue.enqueue('3');
    charQueue.enqueue('4');
    charQueue.enqueue('5');
    charQueue.enqueue('6');
    charQueue.enqueue('7');
    charQueue.enqueue('8');
    while (!charQueue.empty()) {
        char temp = charQueue.dequeue();
        std::cout << temp << " ";
    }

    std::cout << std::endl;

    return 0;
}

linked_queue.h

#ifndef TEST_LINKED_QUEUE_H
#define TEST_LINKED_QUEUE_H

#include <iostream>

template<class T>
class linked_queue {
public:
    linked_queue() : head(Node()), tail(&head) {}

    ~linked_queue() {
        Node *cur = head.next; 
        while (cur) {
            Node *prev = cur;
            cur = cur->next;
            delete prev;
        }
    }

    [[nodiscard]] bool empty() const { return head.next == nullptr; }

    T dequeue() {
        T ret = head.next->data;
        head.next = head.next->next;
        return ret;
    }

    void enqueue(const T &x) {
        tail->next = new Node(x);
        tail = tail->next;
    }

    [[maybe_unused]] [[nodiscard]] bool full() const { return false; }

private:
    struct Node {
        Node *next;
        T data;

        explicit Node(const T &data = NULL) : next(nullptr), data(data) {}
    };

    Node head;   
    Node *tail;  
};

namespace linked {
    using Char_queue = linked_queue<char>;
}

#endif //TEST_LINKED_QUEUE_H

当我运行这个的时候,我得到了一个反馈:

=================================================================
==14617==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e48c in main main.cpp:21
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e4f0 in main main.cpp:26
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e4dc in main main.cpp:25
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e4c8 in main main.cpp:24
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e4b4 in main main.cpp:23
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e4a0 in main main.cpp:22
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e504 in main main.cpp:27
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

Indirect leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x100a62778 in wrap__Znwm+0x48 (libclang_rt.lsan_osx_dynamic.dylib:arm64+0x6778)
    #1 0x10068e778 in linked_queue<char>::enqueue(char const&) linked_queue.h:33
    #2 0x10068e518 in main main.cpp:28
    #3 0x1836f1f30 in start+0x0 (libdyld.dylib:arm64+0x16f30)

SUMMARY: LeakSanitizer: 128 byte(s) leaked in 8 allocation(s).

好像是tail->next = new Node(x);造成了泄漏,但我相信实际上应该不会发生泄漏。你们能帮帮我吗?

因为 enqueue 调用 newdequeue 不调用 delete,如果你 enqueue 然后 dequeue,你会泄漏。

您的代码一直有效,直到您从不使用 dequeue :D。当你调用 dequeue 时,你没有指针指向你的 dequeued Node,然后这个 Node 导致内存泄漏。您必须在函数 dequeue 中删除此节点,或者保存指向此节点的指针并在析构函数中将其删除。我更喜欢第一种方法,因为无论如何你都不需要出列的节点。