C++ g++4.9.0允许我们在布局分配中使用运算符delete[](void*,size_t)

C++ g++4.9.0允许我们在布局分配中使用运算符delete[](void*,size_t),c++,memory-management,g++,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[

我正在使用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;
}
该示例必须反映第3.7.4.2/2节中的以下脚注规则:

全局运算符delete[]正好有两个参数,第二个是 其类型为std::size\u t,是一个常用的释放函数。37

37此解除分配功能禁止使用分配功能 void操作符newstd::size\u t,std::size\u t作为放置分配 作用


但事实并非如此。这是一个bug,或者脚注只是对实现者的一个建议?

我相信您得到了未定义的行为。我认为,如果构造函数失败,并且必须取消分配数组,则无法区分正确的位置删除函数和大小删除函数。

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

这是非法的,编译器应该发出诊断。从§5.3.4【新增解释】/p22中,增加了强调:

placement-deallocation函数的声明与 如果placement分配函数具有相同的 参数数量,参数转换8.3.5后,所有 除第一个参数类型外,其他参数类型都相同。如果查找发现 单个匹配的释放函数,将调用该函数; 否则,将不会调用释放函数。如果查找 查找常用释放函数的双参数形式 3.7.4.2和该功能,视为配售-解除配售 函数,将被选择为分配的匹配项 函数,程序的格式不正确。对于非安置分配 函数,则使用常规解除分配函数查找来查找 匹配解除分配功能5.3.5[示例:

-[结束示例]

在代码上发出一个错误

但是,请注意,与全局运算符delete和运算符delete[]不同,作为类成员的两个参数运算符delete和运算符delete[]不一定是常用的释放函数§3.7.4.2[basic.stc.dynamic.deallocation]/p2:

如果类T具有名为operator delete的成员释放函数 如果只有一个参数,那么该函数是常用的 释放函数。如果类T未声明此类运算符,则删除 但是声明了一个名为operator delete的成员释放函数 只有两个参数,第二个参数的类型为 std::size\u t,则此函数是一个常用的释放函数。 类似地,如果类T有一个名为 运算符delete[]只包含一个参数,则该函数为 一个常用的非放置-释放函数。如果T类没有 声明这样的运算符delete[]但不声明成员 名为operator delete[]的释放函数,正好有两个 参数,第二个参数的类型为std::size\t,则 函数是一个常用的释放函数

因此,与全局释放函数不同,如果声明成员运算符delete[]void*,然后声明运算符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报告此代码有错误。

这是非法的,编译器应该发出诊断。从§5.3.4【新增解释】/p22中,增加了强调:

placement-deallocation函数的声明与 如果placement分配函数具有相同的 参数数量,参数转换8.3.5后,所有 除第一个参数类型外,其他参数类型都相同。如果查找发现 单个匹配的释放函数,将调用该函数; 否则,将不会调用释放函数。如果查找 查找常用释放函数的双参数形式 3.7.4.2和该功能,视为配售-解除配售 函数,将被选择为分配的匹配项 函数,程序的格式不正确。对于非安置分配 函数,则使用常规解除分配函数查找来查找 匹配解除分配功能5.3.5[示例:

-[结束示例]

在代码上发出一个错误

但是,请注意,与全局运算符delete和运算符delete[]不同,作为类成员的两个参数运算符delete和运算符delete[]不一定是常用的释放函数§3.7.4.2[basic.stc.dynamic.deallocation]/p2:

如果类T具有名为operator delete的成员释放函数 如果只有一个参数,那么该函数是常用的 释放函数。如果类T未声明此类运算符,则删除 但他是否宣布了一名成员 名为运算符delete的释放函数 只有两个参数,第二个参数的类型为 std::size\u t,则此函数是一个常用的释放函数。 类似地,如果类T有一个名为 运算符delete[]只包含一个参数,则该函数为 一个常用的非放置-释放函数。如果T类没有 声明这样的运算符delete[]但不声明成员 名为operator delete[]的释放函数,正好有两个 参数,第二个参数的类型为std::size\t,则 函数是一个常用的释放函数

因此,与全局释放函数不同,如果声明成员运算符delete[]void*,然后声明运算符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报告此代码有错误。

如果它们属于全局名称空间而不是结构A怎么办?@aschepler-Hmm。。。如何通过delete表达式从全局命名空间调用双参数释放函数@我收到了完全相同的结果。您不能通过delete表达式调用任何类型的placement-deallocation函数。它们仅用于新表达式期间的异常。@DmitryFucintv请注意,g++全局大小的释放尚未完成。如果它们属于全局名称空间而不是结构a怎么办?@aschepler-Hmm。。。如何通过delete表达式从全局命名空间调用双参数释放函数@我收到了完全相同的结果。您不能通过delete表达式调用任何类型的placement-deallocation函数。它们仅用于新表达式期间的异常。@DmitryFucintv注意,g++全局大小的释放尚未完成。这有点不清楚。证券交易委员会中没有关于UB的内容。3.7.4.2. 请您再澄清一点好吗?@DmitryFucintv规范中并不是所有未定义的行为都被明确指出。如果规范只是无法描述一种情况,那么所发生的也是“未定义的行为”。但是,正如另一个答案所显示的,规范确实涵盖了这种情况,并明确地将其标记为病态。这有点不清楚。证券交易委员会中没有关于UB的内容。3.7.4.2. 请您再澄清一点好吗?@DmitryFucintv规范中并不是所有未定义的行为都被明确指出。如果规范只是无法描述一种情况,那么所发生的也是“未定义的行为”。但是,正如另一个答案所显示的,规范实际上涵盖了这种情况,并专门将其标记为格式不正确。