繁体   English   中英

C++ 免费 memory

[英]C++ Free memory

我想问一下如何在我的程序中正确释放 memory。 (free():在 tcache 2 超时中检测到双重释放:监控命令转储核心)

在 adVersion 方法中,我创建了一个包含当前实例值的链表。 在变量 m_History 中,我引用了以下元素。 在该方法中,我将实例的当前内容添加到此链表的末尾。

在复制构造函数中,我复制了属于给定实例的所有内容和链表。

我附上了程序的重要部分和整个程序的链接https://onecompiler.com/cpp/3xzaa3mfh

//编辑:我几乎没有改变 adVersion 方法,请你检查一下是否可以?

    class CFile
    {
            uint8_t *m_Data;
            uint32_t m_Len;
            uint32_t m_Position;
            uint32_t m_Capacity;
    
            size_t m_LenHistory;
            CFile *m_History;
    
    };
    
    CFile::CFile(void)
    :m_Data(nullptr), m_Len(0), m_Position(0), m_Capacity(0),m_LenHistory(0), m_History(nullptr)
    {
    }
    
    CFile::~CFile (void)
    {
        delete[] m_Data;
    
        //Delete linked list
        while (m_History)
        {
            CFile* old = m_History;
            delete[] old->m_Data;
            m_History = m_History->m_History;
            delete old;
        }
        m_History = nullptr;
    }
    
    CFile* copyLinkedList(CFile *list)
    {
        if(list == nullptr) return nullptr;
    
        CFile* result = new CFile;
        result->m_Capacity = list->m_Capacity;
        result->m_Len = list->m_Len;
        result->m_Position = list->m_Position;
        result->m_LenHistory = list->m_LenHistory;
        result->m_Data = new uint8_t[list->m_Capacity];
        memcpy(result->m_Data, list->m_Data, result->m_Len);
        result->m_History = copyLinkedList(list->m_History);
        
        return result;
    }
    
    // Copy construkctor
    CFile::CFile(const CFile &src)
    : m_Data(new uint8_t[src.m_Capacity]),
      m_Len(src.m_Len),
      m_Position(src.m_Position),
      m_Capacity(src.m_Capacity),
      m_LenHistory(src.m_LenHistory)
    {
        memcpy(m_Data, src.m_Data, m_Len);
        m_History = copyLinkedList(src.m_History);
    }
    
    void CFile::copyWithoudLinkedList( CFile &src )
    {
        m_Capacity = src.m_Capacity;
        m_Len = src.m_Len;
        m_LenHistory = src.m_LenHistory;
        m_Position = src.m_Position;
        m_Data = new uint8_t[src.m_Capacity];
    
        memcpy(m_Data, src.m_Data, m_Len);
    }
    
    void CFile::addVersion  ( void )
{
    CFile *tmp = m_History;
    CFile *prev;

    if(!tmp)
    {
        tmp = new CFile();
        tmp->copyWithoudLinkedList(*this);
        this->m_History = tmp;
        this->m_History->m_History = nullptr;
        m_LenHistory++;
    }
    else
    {
        while(tmp)
        {
            prev = tmp;
            tmp = tmp->m_History;
        }
        
        tmp = new CFile();
        tmp->copyWithoudLinkedList(*this);
        prev->m_History = tmp;
        prev->m_History->m_History = nullptr;
        m_LenHistory++;
   }
}

避免手动 memory 处理出现问题的最佳方法是没有任何问题。 C++ 标准库的大部分都在那里,因此您不必为实现标准数据结构而烦恼。

首先,不要使用uint8_t *m_Data; (这需要分配和释放内存)使用std::vector< uint8_t >为您完成。

其次,将class CFile从做两件事——保存数据和实现列表——变成只做一件事,保存数据。

#include <vector>

struct CFile
{
    std::vector< uint8_t > m_Data;
    // ...
};

第三,通过标准容器std::forward_list获取CFile实例的链表:

#include <forward_list>

std::forward_list< CFile > cfile_list;
CFile cfile { { 0x23, 0x42, 0xff } };
cfile_list.push_front( cfile );

由于您现在不必在任何地方手动分配 memory,因此您也不必手动释放它。

虽然我完全同意其他人的观点,你不应该自己管理 memory,除非你正在开发标准库中不可用的新数据结构,但我也喜欢那些想“自己动手”学习和犯错误的人.

所以,因为我在度假,所以我抓住机会重做我的方式(没有太多关注,所以不要太相信这个)。

基本思想是将文件内容与版本控制系统的管理器分开。 我尽量避免过多地更改您的名称和算法,但列表内容真的太奇怪了,并且充满了可能未初始化的变量。

我没有添加任何与移动构造函数相关的内容,但如果您打算自己管理 memory,它们绝对很重要。 看看复制和交换习语。

看看这是否符合您的需求:

#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <iostream>
#include <algorithm>

// using namespace std; // Not a good idea

class CFile {
    struct CFileContents {
        uint8_t *m_Data = nullptr;
        uint32_t m_Len = 0;
        uint32_t m_Capacity = 0;
        uint32_t m_Position = 0;
    
        CFileContents() {}
        CFileContents(const CFileContents& other) :
            m_Data(new uint8_t[other.m_Capacity]),
            m_Len(other.m_Len),
            m_Capacity(other.m_Capacity),
            m_Position(other.m_Position)
        {
            std::copy(other.m_Data, other.m_Data + other.m_Len, m_Data);
        }
        CFileContents& operator=(const CFileContents& rhs) {
            if (m_Capacity < rhs.m_Capacity) {
                delete[] m_Data;
                m_Capacity = rhs.m_Capacity;
                m_Data = new uint8_t[m_Capacity];
            }
            m_Len = rhs.m_Len;
            std::copy(rhs.m_Data, rhs.m_Data + rhs.m_Len, m_Data);
            m_Position = rhs.m_Position;
            return *this;
        }
        ~CFileContents() {
            delete[] m_Data;
        }

        const uint8_t* data() const { return m_Data; }
        uint32_t length() const { return m_Len; }
        uint32_t pos() const { return m_Position; }

        void truncate(void) {
            m_Len = m_Position;
        }

        uint32_t write(const uint8_t *src, uint32_t bytes) {
            if (m_Position + bytes > m_Capacity)
            {
                while (m_Position + bytes > m_Capacity)
                    m_Capacity += m_Capacity / 2 + 10;

                uint8_t *tmp = new uint8_t[m_Capacity];
                std::copy(m_Data, m_Data + m_Len, tmp);
                delete[] m_Data;
                m_Data = tmp;
            }
            std::copy(src, src + bytes, m_Data + m_Position);

            if (m_Position + bytes > m_Len)
                m_Len = m_Position + bytes;

            m_Position += bytes;
            return bytes;
        }

        uint32_t read(uint8_t* dst, uint32_t bytes)
        {
            if (m_Position + bytes > m_Len) {
                bytes = m_Len - m_Position;
            }
            std::copy(m_Data + m_Position, m_Data + m_Position + bytes, dst);
            m_Position += bytes;
            return bytes;
        }

        bool seek(uint32_t offset) {
            if (offset <= m_Len) {
                m_Position = offset;
                return true;
            }
            return false;
        }

    };

    struct CNode {
        CFileContents data;
        CNode* next = nullptr;

        CNode() {}
        CNode(const CNode& other) = delete;
        CNode& operator=(const CNode& rhs) = delete;
        ~CNode() {
            delete next;
        }
    };

    uint32_t m_LenHistory;
    CNode *m_History;

public:
    CFile(void) : m_LenHistory(1), m_History(new CNode) {}

    friend void swap(CFile& a, CFile& b) {
        using std::swap;
        swap(a.m_LenHistory, b.m_LenHistory);
        swap(a.m_History, b.m_History);
    }

    CFile(const CFile &src) : m_LenHistory(src.m_LenHistory) {
        CNode** dcur = &m_History;
        for (CNode* scur = src.m_History; scur; scur = scur->next) {
            *dcur = new CNode;
            (*dcur)->data = scur->data;
            dcur = &(*dcur)->next;
        }
    }

    CFile& operator=(CFile src) {
        swap(*this, src);
        return *this;
    }

    ~CFile(void) {
        delete m_History;
    }

    uint32_t write(const uint8_t *src, uint32_t bytes) {
        return m_History->data.write(src, bytes);
    }
    uint32_t read(uint8_t* dst, uint32_t bytes) {
        return m_History->data.read(dst, bytes);
    }
    bool seek(uint32_t offset) {
        return m_History->data.seek(offset);
    }
    void truncate(void) {
        m_History->data.truncate();
    }
    uint32_t fileSize(void) const { return m_History->data.length(); }

    void addVersion(void) {   
        CNode* head = new CNode;
        head->data = m_History->data;
        head->next = m_History;
        m_History = head;
        ++m_LenHistory;
    }

    bool undoVersion(void) {
        if (m_LenHistory == 1)
            return false;
        CNode* head = m_History;
        m_History = head->next;
        head->next = nullptr;
        delete head;
        --m_LenHistory;
        return true;
    }

    uint32_t lenHistory() const {
        return m_LenHistory;
    }
};



bool writeTest(CFile& x, const std::initializer_list<uint8_t>& data, uint32_t wrLen)
{
    return x.write(data.begin(), data.size()) == wrLen;
}

bool readTest(CFile& x, const std::initializer_list<uint8_t>& data)
{
    auto* tmp = new uint8_t[data.size()];
    uint32_t idx = 0;
    bool ret = true;

    if (x.read(tmp, data.size()) != data.size())
        ret = false;
    else {
        for (auto v : data) {
            if (tmp[idx++] != v) {
                ret = false;
                break;
            }
        }
    }
    delete[] tmp;
    return ret;
}



int main(void)
{
    {
        CFile f0;
        assert(writeTest(f0, { 10, 20, 30 }, 3));
        assert(f0.fileSize() == 3);
        assert(writeTest(f0, { 60, 70, 80 }, 3));
        assert(f0.fileSize() == 6);
        assert(f0.seek(2));
        assert(writeTest(f0, { 5, 4 }, 2));
        assert(f0.fileSize() == 6);
        assert(f0.seek(1));
        assert(readTest(f0, { 20, 5, 4, 70, 80 }));
        assert(f0.seek(3));
        f0.addVersion();
        assert(f0.seek(6));
        assert(writeTest(f0, { 100, 101, 102, 103 }, 4));
        f0.addVersion();
        assert(f0.seek(5));
        CFile f1(f0);
        f0.truncate();
        assert(f0.seek(0));
        assert(readTest(f0, { 10, 20, 5, 4, 70 }));
        assert(f0.undoVersion());
        assert(f0.seek(0));
        assert(readTest(f0, { 10, 20, 5, 4, 70, 80, 100, 101, 102, 103 }));
        assert(f0.undoVersion());
        assert(f0.seek(0));
        assert(readTest(f0, { 10, 20, 5, 4, 70, 80 }));
        assert(!f0.seek(100));
        assert(writeTest(f1, { 200, 210, 220 }, 3));
        assert(f1.seek(0));
        assert(readTest(f1, { 10, 20, 5, 4, 70, 200, 210, 220, 102, 103 }));
        std::cout << f1.lenHistory() << std::endl;
        //std::cout << f1.m_History->m_Data << std::endl;
        assert(f1.undoVersion());
        std::cout << f1.lenHistory() << std::endl;
        assert(f1.undoVersion());
        assert(readTest(f1, { 4, 70, 80 }));
        assert(!f1.undoVersion());
    }
    _CrtDumpMemoryLeaks(); // remove this if you are not using Visual Studio
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM