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