我有一些代码:
int *ip = new int;
*ip = 42;
cout << *ip << endl;
cout << ip << endl;
delete ip;
cout << *ip << endl;
cout << ip << endl;
输出结果为:
42
0x100105400
42
0x100105400
从指针的值和它所指向的内存上的值,我想我不知道ip
指向的堆中的内存位是否是空闲的?
我知道如果我在代码之后再次添加delete ip;
,编译器将抛出错误。这将是一个很好的证据,表明记忆是免费的。
但是,我怎样才能测试它是否是和平的,所以我可以用它作为判断代码中进一步操作的条件?
答案 0 :(得分:0)
但是,我怎样才能测试它是否是和平的,所以我可以用它作为决定我代码中进一步操作的条件?
释放内存不会改变指针的值,并且不一定会改变它指向的内存(无论如何它都不应该尝试访问)。
在删除指针时,您应该将指针设置为nullptr
,然后您可以检查它是否为nullptr
,以查看它是否已被释放。
示例:
int* ip = new int;
*ip = 42;
delete ip;
ip = nullptr;
// ...
if (ip) {
delete ip;
ip = nullptr;
}
答案 1 :(得分:0)
如果您的代码取决于特定内存是否空闲,则可能存在一些设计问题。但是,如果你确实想要测试,你可以重载operator new
和operator delete
(及其相应的数组/类版本),以便跟踪在您可用的某些全局数据结构中分配的内存位置程序。下面是一些玩具示例(live on ideone.com),它定义了一个位置new
,用于跟踪分配的内存(和大小)。
#include <iostream>
#include <map>
std::map<void*, std::size_t> memory; // globally allocated memory map
struct tag {}; // tag for placement new's so we don't overload the global ones
void* operator new(std::size_t size, const tag&)
{
void* addr = malloc(size);
memory[addr] = size;
return addr;
}
void* operator new[](std::size_t size, const tag&) // for arrays
{
return operator new(size, tag());
}
void operator delete(void *p) noexcept
{
memory.erase(p);
free(p);
}
void operator delete[](void *p) noexcept // for arrays
{
operator delete(p);
}
void display_memory()
{
std::cout << "Allocated heap memory: " << std::endl;
for (auto && elem : memory)
{
std::cout << "\tADDR: " << elem.first << " "
<< "SIZE: " << elem.second << std::endl;
}
}
bool is_allocated(void* p)
{
return (memory.find(p) != memory.end());
}
int main()
{
int *p = new(tag()) int[10];
char *c = new(tag()) char;
// test if p is allocated
std::cout << std::boolalpha << "Allocated: "
<< is_allocated(p) << std::endl;
// display the allocated memory
display_memory();
// remove p
delete[] p;
// test again if p is allocated
std::cout << std::boolalpha << "Allocated: "
<< is_allocated(p) << std::endl;
display_memory();
// remove c
delete c;
display_memory();
}
编辑:我意识到上面的代码可能存在一些问题。在函数
中void operator delete(void *p) noexcept
{
memory.erase(p);
free(p);
}
memory.erase(p)
也会调用operator delete
,因此您最终可能会遇到一些令人讨厌的递归(出于某种原因,上面的代码只会输入一次递归)。修复方法是为使用std::map memory
而不是全局malloc/free
的{{1}}编写自定义分配器。
答案 2 :(得分:0)
为了完整起见,这里是Doug Lea的免费商店实施页面的链接:http://g.oswego.edu/dl/html/malloc.html。
在第一个图表的内存布局中,您可以看到每个分配块的用户数据前面都有记账信息,其中包括&#34; in-use&#34;旗。这些块形成一个链表:从给定的块中,可以在此之后到达所有块(实际上,也可以在此之前)。
知道数据大小和对齐要求,可以猜测给定系统,该信息可能与返回的指针有关;在我的x86_64-pc-cygwin上,状态字节是返回地址前的8个字节,&#34;在使用中&#34; flag是第一个字节的2位。
虽然看起来很有希望,但有一个问题:我可以看到一个delete()coalescs相邻的块,以便簿记信息仅在融合块的开头有效:如果你有两个指针p1,p2指向按顺序分配的免费商店中的内存,并且您再次按顺序删除,p2的簿记位置的内存不会刷新以反映p2已被释放。相反, p1 之前的簿记区域现在指示以下内存块具有组合的单个块的大小。
为了找出给定指针指向的内存是否已被释放,必须遍历内存块的链接列表,可能是从在其他任何内容之前分配的虚拟对象开始。当然可能,但不可取,不健全。 @ vsoftco的想法要好得多。
最后并非最不重要的是:总是从main返回int的人可能会抱怨所有这些都是UB。他们是对的。