在内存中的预定位置构造的对象 - SEGFAULT

时间:2014-05-23 06:23:52

标签: c++ memory-management

我有这段代码

int main()
{    
    int *b = new int(8);
    cout<<" &b = "<<b<<endl;
    delete b;
    void *place = (void*)0x3c0fa8; //in my output i am getting this value in &b
    int *i = new(place) int(8);

    system("PAUSE");
    return 0;
}

我怀疑是我为“b”分配空间,并将其删除,现在如果我分配另一个整数空间,它就会出现与先前分配的位置相同,现在如果我强制将整数值放到此值(删除后),我收到了SEGFAULT。

此代码有什么问题?

感谢。

3 个答案:

答案 0 :(得分:3)

不能保证每次b都会被分配到同一个内存位置,事实上它并不常见,你不应该依赖它。

对于这种情况,place实际上指向了无效的地址,访问它会导致Segfault。

即使place指向分配了b的同一位置,在删除b后,内存也会被取消分配,并且不属于您的程序。在int *i = new(place) int(8);执行之前,该内存位置可能已由任何其他进程分配。因此,再次访问它将导致Segfault。

答案 1 :(得分:1)

使用从堆中分配 的内存,之后它已被释放(使用delete)是未定义的行为。据我们所知,堆的那个单元可能已经完全释放回操作系统[因此在您的进程中不再可用作内存](事实上,Windows几乎直接调用操作系统进行所有堆分配,并且它有可能它释放堆所在的整个内存块)。

然而,第二个new调用更有可能成功,而你只是覆盖了属于堆的一些堆内存,所以当代码试图退出时(并且免费)在main之前分配的一些东西,它会失败。

如果你要这样做

int main()
{    
    int *b = new int(8);
    cout<<" &b = "<<b<<endl;
    // delete b;
    int *i = new(b) int(8);

}

它很有可能工作,因为你已经释放后不再使用堆内存。 (当然,您可能希望将第二个8更改为9或其他内容以查看差异......;)

答案 2 :(得分:0)

看起来您使用展示位置new错误了。展示位置new运算符用于在预定义位置构建内容。它意味着像这样使用(This question也可能有用):

char *buffer  = new char[sizeof(string)];
string *str = new (buffer) string("hello, world");//<-- this is your placement new

如您所见,您正在构建的内存应该事先获得。但是,在您的示例中,您没有这样做,并尝试写入您之前未获得的内存,这会导致段错误。

另外,正如另一个答案所提到的,您无法保证每次都获得b的相同地址。而且,即使你很幸运,并且place指向与b相同的地址,你仍然会尝试写入不属于你的记忆,因为你做了{{1事先。