Reputation: 409
I have a custom delete[] operator:
void operator delete[](void *ptr, char const* file, int line) noexcept {...}
When I try to call it, it calls the simple delete[](void *ptr) an not my custom operator:
char *b = new char[256];
delete[] b, __FILE__, __LINE__;
It compiles, but is my call to the custom operator right?
Upvotes: 3
Views: 2713
Reputation: 153820
When using the delete
expression the default operator delete(void*)
is called. Similar for the array uses. The only case when an overloaded operator delete()
is called by the language is when an exception is thrown by the constructor of the object after the match operator new()
was called.
If you use a custom operator new()
, i.e., using some placement syntax like new(a, b) T(...)
, you'll need to manually destroy the object and release the corresponding memory:
T* ptr = new(__FILE__, __LINE__) T(args);
// ...
ptr->~T(); // destroy the object
operator delete(ptr, __FILE__, __LINE__);
When replacing or overloading the "normal" operator new()
/operator delete()
, i.e., the signatures
void* operator new(std::size_t)
void operator delete(void*)
(and the corresponding array forms), either by replacing the global version or using a class-specific overload, i.e., a corresponding static
member, the destructor and operator delete()
are called by the delete
expression.
Upvotes: 4
Reputation: 145259
The statement
delete[] b, __FILE__, __LINE__;
… is a comma expression, not an invocation of a placement delete
function.
There is no syntax for making a delete
expression call a placement delete
function (deallocation function).
Assuming the purpose of this is to log or inspect the source code location where a block to be deleted, was allocated, you can do that like this:
#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";
}
Typical output:
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)
Upvotes: 1
Reputation: 15162
According to https://en.wikipedia.org/w/index.php?title=Placement_syntax&action=edit§ion=9 there is no placement delete syntax. You need the 'placement' operator delete overload to match the operator new but you cannot invoke it the way you can with placement new.
The operator delete overload is called in case of an exception in the ctor of the object being constructed and at no other time.
Upvotes: 1