【问题标题】:how to call custom delete operator如何调用自定义删除运算符
【发布时间】:2017-12-16 18:07:25
【问题描述】:

我有一个自定义的 delete[] 运算符:

void operator delete[](void *ptr, char const* file, int line) noexcept {...}

当我尝试调用它时,它调用了简单的 delete[](void *ptr) 而不是我的自定义运算符:

char *b = new char[256];
delete[] b, __FILE__, __LINE__;

它可以编译,但我对自定义运算符的调用正确吗?

【问题讨论】:

    标签: c++ call delete-operator


    【解决方案1】:

    使用delete 表达式时,会调用默认的operator delete(void*)。类似的阵列用途。语言调用重载的operator delete() 的唯一情况是在调用匹配operator new() 之后对象的构造函数抛出异常。

    如果您使用自定义operator new(),即使用new(a, b) T(...)之类的放置语法,则需要手动销毁对象并释放相应的内存:

    T* ptr = new(__FILE__, __LINE__) T(args);
    // ...
    ptr->~T(); // destroy the object
    operator delete(ptr, __FILE__, __LINE__);
    

    当替换或重载“正常”operator new()/operator delete(),即签名时

    void* operator new(std::size_t)
    void  operator delete(void*)
    

    (和相应的数组形式),通过替换全局版本或使用特定于类的重载,即相应的static 成员、析构函数和operator delete()delete 表达式调用。

    【讨论】:

    • "你需要手动销毁对象并释放相应的内存" 不。只需在类中实现普通的operator delete()(释放函数),并从放置operator delete中调用它。然后让delete 表达式负责调用析构函数。
    • @Cheersandhth.-Alf:这仅适用于替换版本,不适用于重载(std::nothrow 变体除外)。如果您将参数传递给 new 表达式,则需要按照我的回答中所述手动释放对象。
    • 你说得有道理,假设“替换版本”是指类中的重载,而“重载”是指全局命名空间中的函数。对不起,我没有想到。尽管如此,相同的new 表达式语法仍用于类特定的分配函数。因此,带有隐含全称量化的“如果你使用...”段落是错误的。
    【解决方案2】:

    根据https://en.wikipedia.org/w/index.php?title=Placement_syntax&action=edit&section=9,没有放置删除语法。您需要 'placement' 运算符删除重载来匹配运算符 new,但您不能像使用placement new 那样调用它。

    如果正在构造的对象的 ctor 发生异常,则不会调用运算符 delete 重载。

    【讨论】:

      【解决方案3】:

      声明

      delete[] b, __FILE__, __LINE__;
      

      ... 是一个逗号表达式,而不是对放置 delete 函数的调用。

      没有使delete 表达式调用放置delete 函数(释放函数)的语法。

      假设这样做的目的是记录或检查分配要删除的块的源代码位置,您可以这样做:

      #include <stddef.h>     // size_t
      #include <type_traits>  // std::aligned_storage
      #include <iostream>
      #include <memory>       // std::unique_ptr
      #include <new>          // ::new()
      
      namespace my{
          using std::clog;
          using std::aligned_storage;
      
          using Byte = unsigned char;
      
          struct Sourcecode_location
          {
              char const*     file;
              int             line;
          };
      
          constexpr size_t info_size  = sizeof( Sourcecode_location );
          constexpr size_t info_align = alignof( Sourcecode_location );
      
          auto location_info_ptr( void* const p_array, size_t const size )
              -> Sourcecode_location*
          {
              const size_t n = ((info_align - 1) + size)/info_align;
              return reinterpret_cast<Sourcecode_location*>(
                  reinterpret_cast<Byte*>( p_array ) + n*info_align
                  );
          }
      
          class Foo
          {
              using This_class = Foo;
      
              static void report_delete_of( void* ptr, Sourcecode_location const& loc )
              {
                  clog << "Foo[] " << ptr << " deleted, was allocated at " << loc.file << "(" << loc.line << ")\n";
              }
      
              static void deallocate_array( void* p ) { ::operator delete[]( p ); }
      
          public:
              auto operator new[]( size_t const size )
                  -> void*
              { return This_class::operator new[]( size, "<unknown>", 0 ); }
      
              // If this function is defined it's called instead of the one after here:
              // void operator delete[]( void* const ptr )
      
              void operator delete[]( void* const ptr, size_t const size )
                  noexcept
              {
                  clog << "(The size of the following was " << size << " bytes.)\n";
                  report_delete_of( ptr, *location_info_ptr( ptr, size ) );
                  deallocate_array( ptr );
              }
      
              auto operator new[]( size_t const size, char const* const file, int const line )
                  -> void*
              {
                  const size_t n = ((info_align - 1) + size)/info_align;  // To cover array.
                  void* const p = ::operator new[]( n*info_align + info_size );
                  ::new( location_info_ptr( p, size ) ) Sourcecode_location{ file, line };
                  clog << "new Foo[] " << p << " of size " << size << " at " << file << "(" << line << ")\n";
                  return p;
              }
      
              // Called by construction failure in a placement new expression:
              void operator delete[]( void* const ptr, char const* const file, int const line )
                  noexcept
              {
                  clog << "(The following array's size was not given)\n";
                  report_delete_of( ptr, {file, line} );
                  deallocate_array( ptr );
              }
      
          public:
              ~Foo() {}   // Without this MSVC 29017 provides wrong size to deallocation function.
      
              Foo() {}
          };
      }  // namespace my
      
      auto main()
          -> int
      {
          using namespace std;
      
          auto p = unique_ptr<my::Foo[]>{ new( __FILE__, __LINE__ ) my::Foo[3] };
          clog << "\n";
      }
      

      典型输出:

      new Foo[] 0x3aa08,大小为 7,位于 a.cpp(89) (以下大小为 7 个字节。) Foo[] 0x3aa08 已删除,分配在 a.cpp(89)

      【讨论】:

        猜你喜欢
        • 2012-06-22
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-04
        相关资源
        最近更新 更多