如何调用自定义删除操作符
how to call custom delete operator
我有一个自定义的 delete[] 运算符:
void operator delete[](void *ptr, char const* file, int line) noexcept {...}
当我尝试调用它时,它调用了简单的 delete[](void *ptr) 而不是我的自定义运算符:
char *b = new char[256];
delete[] b, __FILE__, __LINE__;
可以编译,但是我对自定义运算符的调用正确吗?
当使用 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__);
替换或重载 "normal" operator new()
/operator delete()
时,即签名
void* operator new(std::size_t)
void operator delete(void*)
(和相应的数组形式),通过替换全局版本或使用特定于 class 的重载,即相应的 static
成员、析构函数和 operator delete()
由 delete
表达式调用。
根据 https://en.wikipedia.org/w/index.php?title=Placement_syntax&action=edit§ion=9 没有放置删除语法。您需要 'placement' operator delete 重载来匹配 operator new 但您不能像使用 placement new 那样调用它。
operator delete 重载在正在构造的对象的构造函数中出现异常时调用,而在其他任何时候都不会调用。
声明
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)
我有一个自定义的 delete[] 运算符:
void operator delete[](void *ptr, char const* file, int line) noexcept {...}
当我尝试调用它时,它调用了简单的 delete[](void *ptr) 而不是我的自定义运算符:
char *b = new char[256];
delete[] b, __FILE__, __LINE__;
可以编译,但是我对自定义运算符的调用正确吗?
当使用 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__);
替换或重载 "normal" operator new()
/operator delete()
时,即签名
void* operator new(std::size_t)
void operator delete(void*)
(和相应的数组形式),通过替换全局版本或使用特定于 class 的重载,即相应的 static
成员、析构函数和 operator delete()
由 delete
表达式调用。
根据 https://en.wikipedia.org/w/index.php?title=Placement_syntax&action=edit§ion=9 没有放置删除语法。您需要 'placement' operator delete 重载来匹配 operator new 但您不能像使用 placement new 那样调用它。
operator delete 重载在正在构造的对象的构造函数中出现异常时调用,而在其他任何时候都不会调用。
声明
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)