混合运算符和表达式new / delete

时间:2016-12-12 11:20:14

标签: c++ memory new-operator delete-operator

请考虑以下代码:

unsigned char* a = new unsigned char[100];
void* a1 = reinterpret_cast<void*>(a);
operator delete[](a1);

short* b = new short[100];
void* b1 = reinterpret_cast<void*>(b);
operator delete[](b1);

在我看来,它是标量类型的有效语法,因为delete-expression相当于调用析构函数和运算符delete。 POD类型相同:

struct POD {
    int i;
    float f;
    char c;
};
POD* c = new POD[100];
void* c1 = reinterpret_cast<void*>(c);
operator delete[](c1);

使用operator new分配标量和POD类型并使用delete表达式释放的另一件事:

void* d = operator new[](sizeof(unsigned char) * 100);
unsigned char* d1 = reinterpret_cast<unsigned char*>(d);
delete[] d1;

void* e = operator new[](sizeof(short) * 100);
short* e1 = reinterpret_cast<short*>(e);
delete[] e1;

void* f = operator new[](sizeof(POD) * 100);
POD* f1 = reinterpret_cast<POD*>(f);
delete[] f1;

所有这些例子似乎都是格式良好的,但我没有设法找到它是否真的如此。有人可以确认或告诉我哪里错了吗?特别是我担心所有这些类型都有不同的对齐,应该传递给operator new / delete:

  

alignof(unsigned char)1
  alignof(短)2
  alignof(POD)4

UPD。有些人似乎把这个问题与Is it safe to delete a void pointer?混为一谈。我问的问题是expression newoperator deleteoperator newexpression delete的混合。根据标准表达形式,使用运算符表单实现。问题是如何将它们混合用于标量和POD类型?

3 个答案:

答案 0 :(得分:3)

完全无效。使用析构函数分配对象数组时,运行时必须记住要调用析构函数的对象数。最简单的方法是在数组之前分配一些额外的内存,并在那里存储计数。这意味着如果您使用析构函数分配3个单字节对象,则会要求operator new(例如)11个字节的内存 - 其中3个保存对象,8个保存计数(在size_t中)

operator delete想要那个11字节内存块的地址 - 而不是保存/保存这三个对象的3字节块的地址。

现在,我知道你在询问有没有析构函数的内置类型 - 关键是,运行时库可能会选择分配计数 简单。

答案 1 :(得分:2)

我认为将 new-expressions delete-expressions 配对调用(甚至关联的)分配函数释放函数 -like operator delete[]()等 - 导致未定义的行为。前者可能会做一些额外的内务处理,而后者则根据我的理解进行“原始记忆”。

这是来自ISO / IEC 14882:2014,第5.3.5条,它似乎明确说明了这一点(我自己设置为粗体):

  

在第一个替代方法(删除对象)中,delete的操作数的值可以是空指针值,指向前一个<创建的非数组对象的指针em> new-expression ,或指向表示此类对象的基类的子对象(1.8)的指针(第10条)。 如果不是,则行为未定义。在第二个替代方法( delete array )中,delete的操作数的值可以是空指针值或由前一个数组new-expression产生的指针值。 81 如果不是,则行为未定义。 [注意:这意味着 delete-expression 的语法必须与new分配的对象类型匹配,而不是的语法新的表达。 - 结束记录]

答案 2 :(得分:0)

  

有些人似乎将此问题与Is it safe to delete a void pointer?混淆。

(^ - 答案是“,但它似乎偶然起作用......在某些情况下”。)

  

我问的是将表达式new与operator delete和operator new混合使用表达式delete。

......如果它是合法的,可能会对上述问题做出很好的回答,不是吗?

"Nope, you can't use ordinary `delete[]`...but you can use `operator delete[]`.
Its type signature takes a `void*` instead of a typed pointer."

但这不是答案(如果它会使编译器看起来有点顽固而不仅仅为你做那些。)无论哪种方式,问题是只给出一个void指针而没有类型信息,编译器对于new中给出的类型所做的任何“积累”,它不一定具有正确的“拆除”代码。

(如果你认为对基本类型做一些特殊或不同的事情可能会很有趣,那么如果你有一个地址消毒器或未定义行为消毒器类型的工具想要扔东西怎么办? short的特殊情况,与其他类型的测量方式不同......也许是因为您特别要求以不同的方式测量短路?)

由于普通删除是以operator delete[]方式实现的,因此没有额外的魔法力量......那就少了!

因此答案基本相同。