【问题标题】:Is it alright to reuse a deleted address allocation?可以重复使用已删除的地址分配吗?
【发布时间】:2015-05-22 07:22:07
【问题描述】:

假设我有这个代码:

Obj*  objects[10];
char* buffers[10];
// ...
buffers[1] = new char[sizeof(Obj)];
objects[1] = new(&buffers[1]) Obj();
// ...
objects[1]->~Obj();
delete[] buffers[1];

在调用delete之后再使用buffers[1]可以吗?

我所说的重用是指再次使用那个地址空间作为分配的地址。

我的意思是使用这段代码

objects[2] = new(&buffers[1]) A();

【问题讨论】:

  • 重用是指重新分配内存并使用它吗?
  • 究竟以何种方式重用它?重用存储空间来存储另一个指针?当然。删除buffers[1] 中的地址后,它可以做什么?没有。
  • 是的,就像再次将该空间用于另一个对象实例
  • @CarloBrew 什么空间?在代码中显示你想要做什么。
  • 如果你之前不打电话给delete[] buffers[1],你可以做objects[2] = new(&buffers[1]) A();。

标签: c++ memory placement-new


【解决方案1】:

首先:placement new 需要一个指针,而不是指向指针的指针

objects[1] = new(&buffers[1]) Obj(); // Nope
objects[1] = new(buffers[1]) Obj();  // Yes

也就是说,在您删除了buffers[1] 指向的内存之后,您需要在使用它来存储另一个对象实例之前分配新内存。

这就是 new[] 和 delete[] 首先的目的:将一块内存标记为“不再需要”或“正在使用”。

不过,您当然可以重用指针 buffers[1] 来指向新的内存位置,但在您发布的代码无效之后这样做:

objects[2] = new(buffers[1]) A();

因为您尝试在已删除的内存位置上构建对象。这将触发未定义的行为。

这是有效的

Obj*  objects[10];
char* buffers[10];
// ...
buffers[1] = new char[sizeof(Obj)];
objects[1] = new(buffers[1]) Obj();
// ...
objects[1]->~Obj();
delete[] buffers[1];

// Allocate something else and build an object there. Remember that
// 'objects' is an array of pointers to Obj objects
buffers[1] = new char[sizeof(Obj)];
objects[1] = new(buffers[1]) Obj();
// You might now destroy and deallocate

【讨论】:

  • 问题,为什么我在cout<<buffers[1]<<endl; 时会得到一些奇怪的字符?我用了你的代码
  • @CarloBrew 这将回答你的问题:stackoverflow.com/questions/17813423/… 不要忘记 buffers[1] 是 char* 类型。
  • @rozina 我明白了,谢谢@Marco A。我对你代码上的delete[] buffers[1]; 很好奇,它不是标记为“不再需要”然后你使用了buffers[1] = new char[sizeof(Obj)]; 吗?还是删除指的是它被指向的地址?
  • @CarloBrew '不再需要'的内存是buffers[1] 指向的内存。不要将该内存区域与指针本身混淆。
  • @CarloBrew 好。如果它解决了您的问题,请不要忘记将其标记为已接受的答案。
【解决方案2】:

Buffers 是一个指针数组。您可以使用 buffers[1] 在其中存储一个新指针。但是,在您将新的有效指针放入其中之前,您不应该取消引用缓冲区 [1]。

我有一种感觉,您想重新分配缓冲区中的空间,但要在其中存储另一个 Obj。只要不删除用buffers[1] = new char[sizeof(Obj)];分配的内存就可以这样做

Obj*  objects[10];
char* buffers[10];
// ...
buffers[1] = new char[sizeof(Obj)];
objects[1] = new(buffers[1]) Obj();
// ...
objects[1]->~Obj();

// you can store a new Obj object in the same place before deleing memory
objects[2] = new(buffers[1]) Obj();
objects[2]->~Obj();
delete[] buffers[1];

但是,您不能将不同类型的对象存储在同一位置,因为它们的大小可能不匹配。在这种情况下,您必须释放分配的内存(使用 delete[]),然后使用 new 重新分配它。

Obj*  objects[10];
char* buffers[10];
// ...
buffers[1] = new char[sizeof(Obj)];
objects[1] = new(buffers[1]) Obj();
// ...
objects[1]->~Obj();    
delete[] buffers[1];

buffers[1] = new char[sizeof(A)];
A* objA = new(buffers[1]) A(); // can't store A in objects[] since its not Obj
objA->~A();
delete[] buffers[1];

【讨论】:

  • 嗯,有趣的答案。我会记住这一点。所以这意味着我可以重复使用该地址,只要我不释放它?
  • 不,无效代码:objects 是指向 Obj 对象的指针,而不是 A 对象。
  • @CarloBrew 好吧,这样看吧。您分配了 sizeof(Obj) 字节的内存并将指向它的指针存储在缓冲区 [1] 中。只要您不释放该内存,您就可以将其用于任何您想要的。但是,您的新编辑显示您希望在其中存储不同的对象(对象 A)。 sizeof(A) 可能与 sizeof(Obj) 不同,因此您可能必须释放内存并分配一个具有对象 A 大小的新块。
【解决方案3】:

如果重用是指将指针objects[1] 分配给分配的内存,那么是的,您可以重用它。

如果你想问,你能不能使用指针所指向的内存,你刚刚用delete[] 释放的内存,那么你不能重用它。您只能使用已分配的内存。

【讨论】:

    【解决方案4】:

    如果你想为一个对象的不同实例重用一个缓冲区,你应该使用placement new来初始化这个预分配内存上的对象。

    char buffer[<size>];
    MyClass *p = new (buffer) MyClass;
    p->~MyClass();
    p = new (buffer) MyClass;
    

    【讨论】:

    • 但是你正在删除底层缓冲区
    猜你喜欢
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    相关资源
    最近更新 更多