C++ 什么';这是C+中3.7.4.2[basic.stc.dynamic.deallocation]/2中脚注37的原因+;14?

C++ 什么';这是C+中3.7.4.2[basic.stc.dynamic.deallocation]/2中脚注37的原因+;14?,c++,memory-management,language-lawyer,c++14,C++,Memory Management,Language Lawyer,C++14,§3.7.4.2/2包含以下句子: 全局运算符delete只包含两个参数,第二个参数为 它的类型为std::size\u t,是一个常用的释放函数。 类似地,只包含一个参数的全局运算符delete[]也被禁用 通常的释放函数。全局运算符delete[]with 正好有两个参数是一个 常用的解除分配函数 37)此解除分配函数禁止将分配函数void运算符new(std::size\u t,std::size\u t)用作 布局分配功能 我不仅不理解这个脚注的原因,而且还注意到脚注中提到的这个位置表在

§3.7.4.2/2包含以下句子:

全局
运算符delete
只包含两个参数,第二个参数为 它的类型为std::size\u t,是一个常用的释放函数。 类似地,只包含一个参数的全局
运算符delete[]
也被禁用 通常的释放函数。全局运算符
delete[]
with 正好有两个参数是一个 常用的解除分配函数

37)此解除分配函数禁止将分配函数
void运算符new(std::size\u t,std::size\u t)
用作 布局分配功能

我不仅不理解这个脚注的原因,而且还注意到脚注中提到的这个位置表在§18.6.1.3位置表[new.delete.placement]中不存在

编辑为了验证他回答中的内容,我测试了以下片段:

#include <iostream>

void* operator new  (std::size_t count, int i1, int i2, int i3){
    void *p = malloc(count);
    if (!p) throw std::bad_alloc{};
    std::cout << "operator new" << '\n';
    return p;
}

void operator delete (void* p, int j1, int j2, int j3)
{
    free(p);
    std::cout << "operator delete" << '\n';
}

class A {
public:
    A() { std::cout << "A()" << '\n'; };
    ~A() { std::cout << "~A()" << '\n'; }
};

int main()
{
    try
    {
        A *p = new(0, 0, 0) A;
        delete p;
    }
    catch (std::bad_alloc&) { exit(1); }
}
#包括
void*运算符新(std::size\u t count,int i1,int i2,int i3){
void*p=malloc(计数);
如果(!p)抛出std::bad_alloc{};
标准::coutC.3.2[diff.cpp11.basic]说明:

C.3.2第3条:基本概念[diff.cpp11.basic]

3.7.4.2

更改:新的常用(非配售)解除定位器

基本原理:按大小分配所需

< > >对原始特征< /强>的影响:有效C++ 2011代码可以声明全局布局分配函数和解除分配函数如下:

void操作符新建(std::size\u t,std::size\u t);

void操作符delete(void*,std::size_t)无异常;

然而,在本国际标准中,
操作员删除的声明
可能与预定义的常用(非放置)
运算符delete
(3.7.4)匹配。如果是这样,则程序的格式不正确,就像类成员分配函数和释放函数(5.3.4)一样

换句话说,这与以前的标准(C++11)相比是一个突破性的变化。在C++11中,允许定义这样的
操作符delete
,而在C++14中,程序的格式可能不正确

编辑-根据评论进一步澄清:
  • 18.6.1.3[new.delete.placement]列出了保留的放置表格。但是,您可以在代码中声明其他(非保留)表格。因此,标准的这一部分不适用于您的问题

  • 3.7.4.2与C++11相比,[basic.stc.dynamic.deallocation]有上述变化,C++11不允许放置表单
    运算符new(std::size\t,std::size\t)
    运算符delete(void*,std::size\t)
    ,因为后者可能与预定义的非放置
    运算符delete
    匹配。此更改在C.3.2[diff.cpp11.basic]中有进一步的说明

  • 您编辑的问题已在的评论(,)中解决,但为了完整起见,我将在此处包括它: 未调用自定义
    运算符delete(void*,int,int,int)
    的原因是
    运算符new(std::size\u t,int,int,int)
    未引发异常。5.3.4[expr.new]在§20-23中解释了这一点


我认为这意味着一个(用户)不能定义一个
操作符new(size\u t,size\u t)
,因为这需要一个相应的
操作符delete(size\u t,size\t)
用于通过此placement new函数在分配中构造时由于抛出异常而发生的删除。@dyp但根据§18.6.1.3,该语言不允许将此placement表单用于
operator new
。我不太明白[new.delete.placement]禁止使用此分配函数。请详细说明一下好吗?注意:我在上一篇评论中使用了术语“requires”,但这一点太强了:不需要相应的释放函数,但如果没有相应的释放函数,则在该场景中会出现泄漏。(我不确定是否会调用库版本。)Placement delete是一个奇怪的beast;它仅在Placement new调用的构造函数抛出时调用。该段仅涉及在构造抛出时处理释放。
delete x;
单独指定(在5.3.5[expr.delete]中)并且只使用普通的释放函数。实际原因:编译器只知道在放置新位置时要传递给放置删除的参数。另请参见:[expr.new]p22(在最近的草稿中;不确定是否已经在C++14中)C++11也没有提到您在§18.6.1.3中引用的安置形式。据我所知,§18.6.1.3规定了语言允许的安置形式。@Belloc:18.6.1.3列出了保留的安置形式。这并不意味着您不能声明其他(即非保留的)但是,您要询问的脚注还说,您也不允许声明
void运算符new(std::size\u t,std::size\u t)
placement分配函数(这在C++11中是允许的,但在C++14中不再允许)对于我来说,代码<保留> <代码>是指在18.61.3/1中所写的,即:<代码>一个C++程序可能无法定义在标准C++库< /代码>中替换版本的函数。换句话说,放置表单是不可替换的。@ Belloc:对于位移,函数签名必须与被移位的版本匹配。由于根据18.6.1.3,未保留
void运算符new(std::size\u t,std::size\u t)
,因此该段不适用。但您提到的脚注适用。