首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何修复堆损坏

如何修复堆损坏
EN

Stack Overflow用户
提问于 2009-10-14 16:45:42
回答 4查看 3.6K关注 0票数 3

我试图构建一个非常简约的内存读取库来读取其中的一些unsigned int。但是,当ReadUnsignedInt方法想返回时,我会遇到一条“检测到的堆损坏”错误消息。

检测到

堆损坏。CRT检测到应用程序在缓冲区结束后写入内存。

正如我所读到的,这可能是在尝试删除一些东西时的原因。这可能是由于std::tr1::shared_ptr的某些不正确使用造成的,但我无法确定我对它们做错了什么。代码如下(省略错误处理):

代码语言:javascript
复制
unsigned int Memory::ReadUnsignedInt (unsigned int address) const {
    std::tr1::shared_ptr<byte> bytes = 
        this->ReadBytes(address, sizeof(unsigned int));
    return *((int*)bytes.get());
    // correct value (how to improve this ugly piece of code?)
}

std::tr1::shared_ptr<byte> Memory::ReadBytes (
    unsigned int address, int numberOfBytes) const
{
    std::tr1::shared_ptr<byte> pBuffer(new byte(numberOfBytes));
    ReadProcessMemory(m_hProcess.get(), (LPCVOID)address, 
        pBuffer.get(), numberOfBytes * sizeof(byte), NULL))
    return pBuffer;
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-10-14 16:51:22

Michael和Naveen都在代码中发现了相同的主要缺陷,但并不是唯一的缺陷。

当指向对象的引用计数为零时,shared_ptr将对其进行delete

这意味着您只能给它分配由new分配的对象--而不是new[]

您可能希望使用shared_ptr<vector<byte> >boost::shared_array

票数 4
EN

Stack Overflow用户

发布于 2009-10-14 16:50:08

问题是:

代码语言:javascript
复制
new byte(numberOfBytes)

这将分配一个值为numberOfBytes的单个字节。

你想做的是:

代码语言:javascript
复制
new byte[numberOfBytes]    

它分配一个字节数组numberOfBytes long。

但是既然你知道你只读了4个字节,为什么还要去分配内存呢?只需在堆栈上传递未签名int的地址即可。

票数 2
EN

Stack Overflow用户

发布于 2009-10-14 17:48:02

您的代码的基本问题已经指出了。看看它,我想知道为什么您会在这里使用shared_ptr。如果我这么做的话,我可能会用这样的方法:

代码语言:javascript
复制
unsigned Memory::ReadUnsignedInt(unsigned address) { 
    unsigned ret;
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret, sizeof(ret), NULL);
    return ret;
}

std::vector<char> Memory::ReadBytes(unsigned address, int num) { 
    std::vector<char> ret(num);
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret[0], num, NULL);
    return ret;
}

再一次,我不想使用ReadUnsignedInt,而是想使用模板:

代码语言:javascript
复制
template <class T>
T Memory::Read(unsigned address) { 
    T ret;
    ReadProcessMemory(m_hProcess.get(), (void*)address, &ret, sizeof(ret), NULL);
    return ret;
}

由于您没有传递一个参数,从中可以推断模板参数的类型,所以您必须始终显式地指定:

代码语言:javascript
复制
int x = Read<int>(wherever);
char a = Read<char>(wherever);

另一种方法是将目的地作为参数传递:

代码语言:javascript
复制
template <class T>
Memory::Read(unsigned address, T &t) { 
    ReadProcessMemory(my_hProcess.get(), (void *)address, &t, sizeof(t), NULL);
};

你可以这样说:

代码语言:javascript
复制
Read(wherever, some_int);
Read(somewhere, some_long);

诸若此类。

如果您担心返回char向量的效率不高,那么您可能不应该-- VC++ (和大多数其他合理的当前编译器一样)具有所谓的“命名返回值优化”,这意味着在这种情况下,它传递一个隐藏的引用到您分配结果的向量,而ReadBytes将使用它直接将数据存放到它将结束的位置。因此,只要打开任何合理的优化,ReadBytes几乎肯定会成为内联函数,因此所涉及的任何内容都不会真正得到“传递”或“返回”。

另一方面,这段代码在较旧的编译器中不能很好地工作--对于足够老的编译器,使用成员模板函数的版本可能甚至无法编译。然而,只要你使用一个合理的当前编译器,生活就应该是美好的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1567557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档