C++ 什么';这是C+中3.7.4.2[basic.stc.dynamic.deallocation]/2中脚注37的原因+;14?
§3.7.4.2/2包含以下句子: 全局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)用作 布局分配功能 我不仅不理解这个脚注的原因,而且还注意到脚注中提到的这个位置表在
运算符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)
,因此该段不适用。但您提到的脚注适用。