2014-09-22 45 views
0

在阅读放置新操作员时发现以下代码。删除内部或外部的位置删除

#include <iostream> 
using namespace std; 

class MyClass { 

public: 
    // Placement new operator 
    void* operator new (size_t sz, void* v) { 
    cout << "Placement new invoked" << endl; 
    return v; 
    } 

    ~MyClass() { 
    // Cleanup 
    } 
}; 

int main() 
{ 
    // Create a buffer to store the object 
    int buffer[16]; 
    cout << "Starting address of my buffer = " << &buffer << endl; 

    // Create the object. Use placement new 
    MyClass* obj = new (buffer) MyClass(); 
    cout << "Location of my object = " << obj << endl; 

    // Don't delete object created with placement delete 
    // Call the destructor explicitly 
    obj->~MyClass(); 
} 

我不得不删除其使用放置新创建的对象相关的几个问题:

  1. 什么是清理代码需要在析构函数写为这是在被占领的OBJ 可用内存缓冲存储器。
  2. 是否需要定义放置删除,如果是,是否需要在析构函数内或析构函数外。如果它在析构函数外部如何被调用?
+0

你只需要显式调用析构函数。没有任何地点删除。 (但请注意,如果底层缓冲区已分配,则可能需要删除..) – 2014-09-22 16:25:34

+0

阅读发布代码末尾的两行注释 – 2014-09-22 16:26:28

+0

没有放置 - 删除 – CashCow 2014-09-22 16:33:54

回答

0

什么是清理代码需要在析构函数来写,以这是在缓冲存储器占用的OBJ可用内存

析构函数应该只是做任何的析构函数:清理任何由对象管理的资源。在这种情况下,它不管理任何资源,所以不需要做任何事情。

根据如何分配对象本身的存储空间,它不应该做任何特殊的事情。必要时管理该存储是自定义newdelete运营商的工作。

难道不是需要定义位置删除

号安置新来构建与您所管理自己存储的对象,这是对自己释放的存储你的责任。在这种情况下,存储是自动的,所以当函数退出时它会自动释放。就像分配器for placement-new什么都不做(只是将提供的指针返回到预先分配的存储)一样,相应的释放器也不会做任何事情;所以它不存在。你只需要在你自己处理存储之前直接调用它的析构函数来销毁对象。

+0

§18.6.1.3定义了一个全局的'operator delete(void *,void *)';如果 他定义了一个类特定的'operator new(size_t,void *)',那么在构造函数抛出的情况下,它可能是定义相应的操作符delete''的好形式。如果没有别的, 将确保删除指向 对象的指针将找不到全局的'operator delete'(这不是 可能适用于他的位置'operator new')。 – 2014-09-22 17:20:48

+0

@JamesKanze,对于上面的代码,你可以定义运算符删除。如果我调用删除obj,而没有定义运算符删除,那会有什么影响? – user3665615 2014-09-22 17:46:13

+0

@Mike,考虑上面的整数私有数据成员的例子,然后MyClass * obj = new(buffer)MyClass();将在缓冲区中为obj分配4字节的内存。现在可以解释如何从缓冲区中删除obj内存,以便缓冲区保持其旧状态。 – user3665615 2014-09-22 18:16:08

0

定期new做了两两件事:

  1. 分配内存为对象
  2. 构造你的对象在内存空间。

安置new意味着你管理其中一个,而另一个管理像以前一样。

  1. 你分配/为你的对象
  2. 构造函数被调用的内存空间提供的内存。

相反的是delete其经常delete执行以下操作:

  1. 调用该对象的析构函数,以清理
  2. 免费这是分配给它的内存。

请注意,由于显而易见的原因,它们以相反的顺序完成。您不能释放包含有关需要清理的信息的内存,直到您已完成使用该内存。而在建设中,你需要先掌握内存。

在你所说的放置删除中,但实际上与放置放置相反,你需要执行销毁的第一步,但不是第二步。因此,你可以调用对象的析构函数,然后你可以释放它使用的内存/用于别的东西。

使用placement new最常见的例子是std::vector,它需要一个连续的数据缓冲区,并且可以让你提前预定(如果你不这样做,它可能会为你做)。该部分分配内存,但不构建它中的对象。因此,稍后构建时,将使用新的放置。

+0

实际上,放置新可能意味着两件不同的事情。在通用意义上,这意味着您可以将其他参数传递给'operator new'函数;类型和它们的含义取决于你。该术语也可以用于新的位置的一个特定变体,其中有一个额外的'void *'参数,它刚刚返回。 – 2014-09-22 17:37:57

0

首先要问的是:你想做什么?如果 定义了班级中的新布置操作员,那么这是 唯一的操作员新操作,当您编写new MyClass时将会找到;你必须总是指定额外的参数。在 几乎所有情况下,你定义一个类特定的operator new,你也应该定义一个类特定的operator delete; 否则当您编写delete p时,全局operator delete函数将被称为 ,而这通常不起作用。

如果你的目标是系统需要 分配和初始化的分离,这就是为什么要定义 成员运营商新的,那么你可以提供一个无操作operator delete;如果该类的构造函数可以抛出,那么 也会提供一个位置操作符删除,因为这是 如果新对象的构造函数通过异常退出 ,将会调用什么。但是,没有其他方式可以调用它。 当提供新的安置操作员时,您必须提供 默认的操作员删除,这是正确的;并且当 为同一类型提供几个新操作符时,您需要 记住某个被调用的每个分配,在 为了在非放置操作符删除中分派。

顺便说一下,刚刚分配的缓冲区作为一个局部变量 不保证足够的定向的任何东西,但 声明缓冲区类型。

编辑:

的需要以何种为operator delete功能(必须是会员)只是一个例子:

void operator delete(void* p) {} 
void operator delete(void* p, void*) {}