【问题标题】:How the operator "delete this" do exactly?运营商“删除这个”究竟是怎么做的?
【发布时间】:2019-07-10 06:36:45
【问题描述】:

我只是测试了关于“删除这个”的操作符。使用句柄系统调用“new/delete”将丢失一个覆盖删除函数调用。

句柄函数如下:

inline void* operator new(size_t size)
{
    void* p = ::malloc( size );
    fprintf( stderr, "new size %ld: %p\n", size, p );
    return p; 
}

inline void* operator new[]( size_t size )
{
    void* p = ::malloc( size );
    fprintf( stderr, "new size[] %ld: %p\n", size, p );
    return p; 
}

inline void  operator delete(void* p)    
{
    fprintf( stderr, "delete: %p\n", p );
    ::free(p); 
}

inline void  operator delete[](void* p)  
{
    fprintf( stderr, "delete []: %p\n", p );
    ::free(p); 
}

和测试类:

class A
{
    public:
        A() : a(NULL)
        {
            printf( "A construct\n" );
            a = new int[100];
        }

        ~A()
        {
            printf( "A destruct \n" );
            freeA();
        }

        void freeA()
        {
            if ( a ) { delete [] a; a = NULL; }
        }

        void release()
        {
            delete this;
        }

    private:
        int*    a;
};

当我打电话时

A* a = new A();
a->release();

结果是:

new size 8: 0x5642fc1c4e70
A construct
new size[] 400: 0x5642fc1c52a0
A destruct 
delete []: 0x5642fc1c52a0

缺少关于 A(0x5642fc1c4e70) 的删除调用,为什么?

【问题讨论】:

  • 你忘记给freeA打电话了吗?
  • @melpomene 我认为这是最小的可重现示例。
  • @BartekPL 不是:ideone.com/P93JmR
  • 如果你使用了ideone页面,那么你只需要使用its template ;)
  • 对不起。我刚刚发现了问题:使用内联,运算符 delete(void* p) 根本无法调用。但是 delete[](void* p) 可以。

标签: c++ delete-operator


【解决方案1】:

https://timsong-cpp.github.io/cppwp/replacement.functions#3

使用程序的定义而不是默认版本 由实现提供([support.dynamic])。这样的替换 在程序启动之前发生([basic.def.odr]、[basic.start])。这 程序的声明不应指定为内联。无诊断 是必需的。

这就是规则。不允许内联。这就是您缺少一个删除并且没有内联说明符的原因。

【讨论】:

    【解决方案2】:

    我刚刚发现了问题:使用内联,运算符 delete(void* p) 根本无法调用。但是 delete[](void* p) 可以。 现在我将关闭它。

    【讨论】:

    • 为什么不能调用?
    • 我也很困惑。但如果我删除内联,它会起作用。你可以试试。我想这可能取决于编译器。
    • 你在这里描述的不是问题。这是您碰巧看到的症状。问题是,既然您已经定义了运算符inline,那么您的程序的行为是未定义的。不调用您期望将被调用的函数是未定义行为的完全可接受甚至合理的结果。
    【解决方案3】:

    我在c++14以下运行你的代码,你的delete操作符可以正确调用。

    https://onlinegdb.com/S1zAgzXbB

    但是,如果运行在 c++14(包括 c++14)版本,则需要将代码从 inline void operator delete(void* p) 更改为 inline void operator delete(void* p,std::size_t sz) 或删除 inline 关键字。那么您的代码将正确运行

    https://onlinegdb.com/BJ3hMz7WH

    希望对你有所帮助。

    【讨论】:

      【解决方案4】:

      既然你已经定义了析构函数,就不需要定义释放函数了。直接在实例的指针上使用delete

      代替

      A* a = new A();
      a->release();
      

      你会有

      A* a = new A();
      delete a;
      

      删除 a 将调用 ~A() 析构函数

      【讨论】:

        猜你喜欢
        • 2014-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-22
        • 1970-01-01
        • 2013-02-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多