正在手动模拟 C++ 中删除运算符的效果;正式非法?

发布于 2024-10-07 21:07:54 字数 524 浏览 7 评论 0原文

我意识到这是不明智的,我不建议这样做,但我很好奇以下内容是否实际上在形式上是非法的:据

#include <iostream>

struct X
{
    ~X()
    {
        std::cout << "~X()\n";
    }
};

int main()
{
    X *x = new X;
    //delete x;
    x->~X();
    ::operator delete(x);
    return 0;
}

我所知,delete x;相当于调用析构函数,然后调用 ::operator delete(x);,但是我根据标准手动执行此操作合法吗?我知道这对于使用新的放置位置来说是有效的,但是在非放置情况下呢?我的预感是,这可能是非法的,因为必须为每个 new 执行 delete (而不是 operator delete),但我会有兴趣肯定知道。

I realise this is ill-advised, and I'm not proposing to do it, but I'm curious as to whether the following is actually formally illegal:

#include <iostream>

struct X
{
    ~X()
    {
        std::cout << "~X()\n";
    }
};

int main()
{
    X *x = new X;
    //delete x;
    x->~X();
    ::operator delete(x);
    return 0;
}

It's my understanding that delete x; is equivalent to invoking the destructor and then calling ::operator delete(x);, but is it legal for me to do that manually according to the standard? I know this is a valid thing to when using placement new, but what about in the non-placement case? My hunch is that it might be illegal because delete (and not operator delete) has to be performed for each new, but I'd be interested to know for sure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(5

—━☆沉默づ 2024-10-14 21:07:54

我很确定这不符合标准。标准(据我所知)中没有任何地方说 delete p; 的操作数直接传递给释放函数,对于 delete [] 它几乎可以肯定不会原样通过。

然而,它可能适用于所有实际实现。

当然,您不应该显式调用全局释放函数。在您的示例中这很好,它没有用户定义的分配和释放函数,但在一般情况下则不然(实际上,是否有任何语法用于调用特定于类的释放函数(如果存在),否则调用全局释放函数? )。

另外,一般情况下,传递给释放函数的指针肯定不是delete的操作数。考虑:

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 B1, virtual D {};

int main( void )
{
  B3* p = new D();
  p->~B3(); // should be ok, calling virtually
  operator delete(p); // definitely NOT OK

  return 0;
}

I'm pretty sure that this is not standard compliant. Nowhere in the standard (that I'm aware of) does it say that the operand of delete p; is passed directly to the deallocation function, and for delete [] it almost certainly isn't passed through unchanged.

It will probably work on all practical implementations, however.

For certain, you shouldn't be calling the global deallocation function explicitly. It's fine in your example, which doesn't have user-defined allocation and deallocation functions, but not in the general case (actually, is there any syntax for calling the class-specific deallocation function if it exists, and the global one otherwise?).

Also, in the general case, the pointer passed to the deallocation function is definitely not the operand of delete. Consider:

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 B1, virtual D {};

int main( void )
{
  B3* p = new D();
  p->~B3(); // should be ok, calling virtually
  operator delete(p); // definitely NOT OK

  return 0;
}
安穩 2024-10-14 21:07:54

如果您要这样做,您应该替换

X *x = new X;

X* x = static_cast<X*>(::operator new(sizeof(X)));

try { new(x) X; }
catch (...) { ::operator delete(x); throw; }

which 应该(如果我错了,请纠正我)与您的破坏方法一致,并且在功能上与 new 几乎相同。

If you are going this way, you should replace

X *x = new X;

by

X* x = static_cast<X*>(::operator new(sizeof(X)));

try { new(x) X; }
catch (...) { ::operator delete(x); throw; }

which should be (please correct me if I'm wrong) consistant with your destruction approach, and pretty much equivalent in functionality to new.

七月上 2024-10-14 21:07:54

我相信,如果您调用析构函数并释放内存,您不会调用未定义的行为。

I believe that you don't invoke undefined behaviour if you call the destructor and free the memory.

¢好甜 2024-10-14 21:07:54

@StuartGolodetz

回答,回复评论

人们很可能可以进行一些模板元编程来确保以其他方式调用全局元编程,但我不是这方面的专家。如果可能的话,我猜这可能是某种 SFINAE 的事情。

struct B {
    virtual ~B();
};

struct D : B {
    operator new (size_t);
    operator delete (void*);
};

B *p = new D;

decltype(typeid(*p))::operator delete (...); // hypothetical C++++

元这个!

@StuartGolodetz

Answer, and reply to a comment

There may well be some template metaprogramming one can do to make sure the global one is called otherwise, but I'm not an expert on that. It's probably an SFINAE thing of some sort if it is possible I'd guess.

struct B {
    virtual ~B();
};

struct D : B {
    operator new (size_t);
    operator delete (void*);
};

B *p = new D;

decltype(typeid(*p))::operator delete (...); // hypothetical C++++

Meta this!

2024-10-14 21:07:54

我认为这

::operator delete(x);

是一样的吗?

delete x;

delete 方法没有被 X 覆盖

I thought that

::operator delete(x);

is the same as

delete x;

if the delete method is not overridden by X?

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