在从放置 new 获得的指针上使用运算符删除的合法性
我确信这段代码应该是非法的,因为它显然不起作用,但它似乎是 C++0x FCD 允许的。
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal? I hope not
也许你们中的一位语言律师可以解释标准如何禁止这样做。
还有一个数组形式:
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal? I hope not
这是最接近的问题 我能够找到。
编辑:我只是不相信标准的语言限制函数 void ::operator delete(void*)
的参数以任何有意义的方式应用于 delete
的操作数> 在删除表达式中。充其量,两者之间的联系是极其脆弱的,并且许多表达式被允许作为操作数来删除
,而这些表达式是无效的到void ::operator delete(void*)
。例如:
struct A
{
virtual ~A() {}
};
struct B1 : virtual A {};
struct B2 : virtual A {};
struct B3 : virtual A {};
struct D : virtual B1, virtual B2, virtual B3 {};
struct E : virtual B3, virtual D {};
int main( void )
{
B3* p = new E();
void* raw = malloc(sizeof (D));
B3* p2 = new (raw) D();
::operator delete(p); // definitely UB
delete p; // definitely legal
::operator delete(p2); // definitely UB
delete p2; // ???
return 0;
}
我希望这表明是否可以将指针传递给void运算符delete(void*)
与是否可以将同一指针用作delete
的操作数无关代码>.
I'm dang certain that this code ought to be illegal, as it clearly won't work, but it seems to be allowed by the C++0x FCD.
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal? I hope not
Maybe one of you language lawyers can explain how the standard forbids this.
There's also an array form:
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal? I hope not
This is the closest question I was able to find.
EDIT: I'm just not buying the argument that the standard's language restricting arguments to function void ::operator delete(void*)
apply in any meaningful way to the operand of delete
in a delete-expression. At best, the connection between the two is extremely tenuous, and a number of expressions are allowed as operands to delete
which are not valid to pass to void ::operator delete(void*)
. For example:
struct A
{
virtual ~A() {}
};
struct B1 : virtual A {};
struct B2 : virtual A {};
struct B3 : virtual A {};
struct D : virtual B1, virtual B2, virtual B3 {};
struct E : virtual B3, virtual D {};
int main( void )
{
B3* p = new E();
void* raw = malloc(sizeof (D));
B3* p2 = new (raw) D();
::operator delete(p); // definitely UB
delete p; // definitely legal
::operator delete(p2); // definitely UB
delete p2; // ???
return 0;
}
I hope this shows that whether a pointer may be passed to void operator delete(void*)
has no bearing on whether that same pointer may be used as the operand of delete
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
标准规则位于 [basic.stc.dynamic.deallocation]p3
您的
delete
调用将调用库的operator delete(void*)
,除非您已覆盖它。既然你没有说过这件事,我就假设你没有说过。上面的“应该”实际上应该类似于“如果没有则行为未定义”,因此它不会被误认为是一个可诊断的规则,[lib.res.on.arguments]p1 不是这样的。 n3225 已更正此问题,因此不会再出错。
The Standard rules at [basic.stc.dynamic.deallocation]p3
Your
delete
call will call the libraries'operator delete(void*)
, unless you have overwritten it. Since you haven't said anything about that, I will assume you haven't.The "shall" above really should be something like "behavior is undefined if not" so it's not mistaken as being a diagnosable rule, which it isn't by [lib.res.on.arguments]p1. This was corrected by n3225 so it can't be mistaken anymore.
编译器并不真正关心
p
来自放置new
调用,因此它不会阻止您对对象发出delete
。这样,您的示例就可以被认为是“合法的”。但这是行不通的,因为无法显式调用“placement
delete
”运算符。仅当构造函数抛出异常时才会隐式调用它们,以便析构函数可以运行。The compiler doesn't really care that
p
comes from a placementnew
call, so it won't prevent you from issuingdelete
on the object. In that way, your example can be considered "legal".That won't work though, since "placement
delete
" operators cannot be called explicitly. They're only called implicitly if the constructor throws, so the destructor can run.你可能会逃脱它(在特定编译器上)
new
/delete
是按照malloc
/free 实现的,
和new
实际上使用与标准new
相同的机制来跟踪与分配相关的析构函数,因此对delete 的调用
可以找到正确的析构函数。但它不可能便携或安全。
I suppose you might get away with it (on a particular compiler) if
new
/delete
are implemented in terms ofmalloc
/free
andnew
actually uses the same mechanism for keeping track of the destructor associated with allocations as the standardnew
, so that the call todelete
could find the right destructor.But there is no way it can be portable or safe.
我在标准的库部分找到了这一点,这是尽可能反直觉的位置(IMO):
C++0x FCD(和n3225草案)第18.6.1.3节,
[new.delete.placement ]
:不过,定义传递给删除的合法表达式的部分是 5.3.5,而不是 3.7.4。
I found this in the library section of the standard, which is about as counter-intuitive a location (IMO) as possible:
C++0x FCD (and n3225 draft) section 18.6.1.3,
[new.delete.placement]
:Still, the section defining legal expressions to pass to
delete
is 5.3.5, not 3.7.4.