在从放置 new 获得的指针上使用运算符删除的合法性

发布于 2024-10-07 01:00:19 字数 1615 浏览 3 评论 0原文

我确信这段代码应该是非法的,因为它显然不起作用,但它似乎是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

单身狗的梦 2024-10-14 01:00:19

标准规则位于 [basic.stc.dynamic.deallocation]p3

否则,提供给标准库中的operator delete(void*)的值应是先前调用operator new(size_t)返回的值之一> 或标准库中的operator new(size_t, const std::nothrow_t&),以及提供给标准库中的operator delete[](void*)的值应是先前调用 operator new[](size_t)operator new[](size_t, const std::nothro_t&) 返回的值之一标准库。

您的 delete 调用将调用库的operator delete(void*),除非您已覆盖它。既然你没有说过这件事,我就假设你没有说过。

上面的“应该”实际上应该类似于“如果没有则行为未定义”,因此它不会被误认为是一个可诊断的规则,[lib.res.on.arguments]p1 不是这样的。 n3225 已更正此问题,因此不会再出错。

The Standard rules at [basic.stc.dynamic.deallocation]p3

Otherwise, the value supplied to operator delete(void*) in the standard library shall be one of the values returned by a previous invocation of either operator new(size_t) or operator new(size_t, const std::nothrow_t&) in the standard library, and the value supplied to operator delete[](void*) in the standard library shall be one of the values returned by a previous invocation of either operator new[](size_t) or operator new[](size_t, const std::nothrow_t&) in the standard library.

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.

怪我入戏太深 2024-10-14 01:00:19

编译器并不真正关心 p 来自放置 new 调用,因此它不会阻止您对对象发出 delete 。这样,您的示例就可以被认为是“合法的”。

但这是行不通的,因为无法显式调用“placement delete”运算符。仅当构造函数抛出异常时才会隐式调用它们,以便析构函数可以运行。

The compiler doesn't really care that p comes from a placement new call, so it won't prevent you from issuing delete 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.

烟花肆意 2024-10-14 01:00:19

你可能会逃脱它(在特定编译器上)

  1. 我想如果new/delete 是按照 malloc/free 实现的,
  2. 放置 new 实际上使用与标准 new 相同的机制来跟踪与分配相关的析构函数,因此对 delete 的调用 可以找到正确的析构函数。

但它不可能便携或安全。

I suppose you might get away with it (on a particular compiler) if

  1. new/delete are implemented in terms of malloc/free and
  2. the placement new actually uses the same mechanism for keeping track of the destructor associated with allocations as the standard new, so that the call to delete could find the right destructor.

But there is no way it can be portable or safe.

晚风撩人 2024-10-14 01:00:19

我在标准的库部分找到了这一点,这是尽可能反直觉的位置(IMO):

C++0x FCD(和n3225草案)第18.6.1.3节,[new.delete.placement ]

这些函数是保留的,是C++的
程序不能定义以下函数
替换标准中的版本
C++ 库 (17.6.3)。规定
(3.7.4) 的规定不适用于这些
运营商预留安置形式
new 和运算符删除。

void*  operator  new(std::size_t  size,  void*  ptr)  throw();
void*  operator  new[](std::size_t  size,  void*  ptr)  throw();
void  operator  delete(void*  ptr,  void*)  throw();
void  operator  delete[](void*  ptr,  void*)  throw();

不过,定义传递给删除的合法表达式的部分是 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]:

These functions are reserved, a C ++
program may not define functions that
displace the versions in the Standard
C ++ library (17.6.3). The provisions
of (3.7.4) do not apply to these
reserved placement forms of operator
new and operator delete.

void*  operator  new(std::size_t  size,  void*  ptr)  throw();
void*  operator  new[](std::size_t  size,  void*  ptr)  throw();
void  operator  delete(void*  ptr,  void*)  throw();
void  operator  delete[](void*  ptr,  void*)  throw();

Still, the section defining legal expressions to pass to delete is 5.3.5, not 3.7.4.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文