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