g ++ 4.9.0允许我们使用operator delete [](void *,size_t)和放置分配

时间:2014-07-25 15:25:19

标签: c++ memory-management g++

我正在使用g ++ 4.9.0和N3797工作草案。我写了以下简单的例子:

#include <iostream>
#include <cstdlib>

using namespace std;

struct A
{
    void* operator new[](size_t t, size_t)
    {
        cout << "allocation" << endl;
        return ::operator new[](t);
    }

    void operator delete[](void *p, size_t t)
    {
        cout << "deallocation" << endl;
        :: operator delete[](p);
    }
};

int main()
{
    A *a = new (90) A[5];
    delete [] a;
}

demo

该示例必须反映3.7.4.2/2节中的以下脚注规则:

  

全局运算符delete []只有两个参数,第二个   其中的类型为std :: size_t,是一种常见的释放函数.37

     

37)该解除分配功能排除了使用分配功能   void operator new(std :: size_t,std :: size_t)作为放置分配   功能

但它没有。这是一个bug或脚注只是对实现者的推荐?

2 个答案:

答案 0 :(得分:4)

这是非法的,编译器应该发出诊断信息。从§5.3.4[expr.new] / p22开始,强调增加了:

  

展示位置释放函数的声明与   如果具有相同的位置分配功能的声明   参数数量,参数变换后(8.3.5)全部   参数类型除了第一个是相同的。如果查找找到了   单匹配解除分配函数,该函数将被调用;   否则,不会调用解除分配函数。 如果查找   找到通常的释放函数的双参数形式   (3.7.4.2)和该函数,被视为放置释放   功能,将被选为匹配的分配   功能,程序格式不正确。对于非展示位置分配   函数,正常的释放函数查找用于查找   匹配释放函数(5.3.5)[示例

struct S {
     // Placement allocation function:
    static void* operator new(std::size_t, std::size_t);
    // Usual (non-placement) deallocation function:
    static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function matches
                  // placement allocation function
     

- 结束示例]

对您的代码判断generates错误。

但请注意,与全局operator deleteoperator delete[]不同,作为类成员的双参数operator deleteoperator delete[]不一定是通常的释放函数(§3.7。 4.2 [basic.stc.dynamic.deallocation] / p2):

  

如果类T具有名为operator delete的成员释放函数   只有一个参数,那么该函数是通常的   释放功能。如果班级T未声明此类operator delete   但确实声明了一个名为operator delete的成员释放函数   正好有两个参数,第二个参数有类型   std::size_t,那么这个函数是一个通常的释放函数。   同样,如果类T具有名为的成员释放函数   operator delete[]只有一个参数,那么该函数是   通常的(非放置)释放功能。如果T级没有   声明这样的operator delete[]但确实声明了一个成员   名为operator delete[]的释放函数恰好有两个   参数,其中第二个类型为std::size_t,然后是这个   函数是一种常见的释放函数。

因此,与全局释放函数不同,如果声明成员operator delete[] (void *),则operator delete[] (void *, std::size_t)不再是通常的释放函数,而是放置释放函数:

struct A
{
    void* operator new[](size_t t, size_t)
    {
        cout << "allocation" << endl;
        return ::operator new[](t);
    }

    void operator delete[](void *p)
    {
        cout << "deallocation - usual" << endl;
        :: operator delete[](p);
    }
    void operator delete[](void *p, size_t t)
    {
        cout << "deallocation - placement" << endl;
        :: operator delete[](p);
    }
};

clang no longer报告此代码出错。

答案 1 :(得分:0)

我相信你会得到未定义的行为。我认为如果构造函数失败并且数组必须被释放,则无法区分正确的放置删除函数和大小的删除函数。