如何调用自定义删除操作符

时间:2017-12-16 18:07:25

标签: c++ call delete-operator

我有一个自定义删除[]运算符:

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

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

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

它编译,但是我对自定义操作员的调用是对吗?

3 个答案:

答案 0 :(得分:3)

使用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()由{{ 1}}表达。

答案 1 :(得分:1)

声明

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 of size 7 at a.cpp(89)

(The size of the following was 7 bytes.)
Foo[] 0x3aa08 deleted, was allocated at a.cpp(89)

答案 2 :(得分:0)

根据https://en.wikipedia.org/w/index.php?title=Placement_syntax&action=edit&section=9,没有展示位置删除语法。你需要这样的安置&#39;运算符删除重载以匹配运算符new,但不能以新的位置调用它。

如果正在构建的对象的ctor中出现异常,则不会在其他时间调用operator delete重载。