I think this is a reasonable limitation of cpp_delete and I only create this issue to document the limitation. See also previous discussion in #8277 (comment)
C++ classes with a virtual destructor have a deleting and non-deleting variant in the vtbl (for Windows it is the same function, but using a parameter to distinguish them). Using delete in C++ calls the deleting destructor, which internally calls the normal destructors and then frees the memory. Function core.stdcpp.new_.cpp_delete instead calls the non-deleting destructor and then frees the memory directly using __cpp_delete. For most classes this is the same, but for C++ classes with custom operator delete it is different.
Here are files to demonstrate it:
cpp_custom_allocator.h:
#include <new>
class C
{
public:
virtual ~C();
void *operator new(std::size_t size);
void operator delete(void *ptr);
};
C *createC();
void deleteC(C *o);
cpp_custom_allocator.cpp:
#include "cpp_custom_allocator.h"
#include <stdio.h>
#include <cstdlib>
C::~C()
{
printf("C::~C()\n");
}
void *C::operator new(std::size_t size)
{
void *p = std::malloc(size ? size : 1);
printf("C::operator new(%zd) => %p\n", size, p);
if (!p)
throw std::bad_alloc();
return p;
}
void C::operator delete(void *ptr)
{
printf("C::operator delete(%p)\n", ptr);
}
C *createC()
{
return new C;
}
void deleteC(C *o)
{
delete o;
}
cpp_custom_allocator.d:
import core.stdc.stdio;
import core.stdcpp.new_;
extern(C++) class C
{
public:
~this();
};
extern(C++) C createC();
extern(C++) void deleteC(C o);
void main()
{
printf("Test with new/delete in C++:\n");
C o = createC();
deleteC(o);
printf("Test with new in C++ an delete in D:\n");
o = createC();
cpp_delete(o);
}
It can be tested with:
clang++ cpp_custom_allocator.cpp -c -o cpp_custom_allocator_cpp.o
dmd cpp_custom_allocator_cpp.o -L-lstdc++ -run cpp_custom_allocator.d
The output is:
Test with new/delete in C++:
C::operator new(8) => 0x556622c4b0f0
C::~C()
C::operator delete(0x556622c4b0f0)
Test with new in C++ an delete in D:
C::operator new(8) => 0x556622c4b1d0
C::~C()
In the first case it deletes from C++ and C::operator delete is called. In the second case it deletes from D using cpp_delete and C::operator delete is not called.
Fixing this would currently break freeing C++ classes allocated in D, because they don't have a real deleting destructor, see issue #23458.
I think this is a reasonable limitation of cpp_delete and I only create this issue to document the limitation. See also previous discussion in #8277 (comment)
C++ classes with a virtual destructor have a deleting and non-deleting variant in the vtbl (for Windows it is the same function, but using a parameter to distinguish them). Using
deletein C++ calls the deleting destructor, which internally calls the normal destructors and then frees the memory. Functioncore.stdcpp.new_.cpp_deleteinstead calls the non-deleting destructor and then frees the memory directly using __cpp_delete. For most classes this is the same, but for C++ classes with customoperator deleteit is different.Here are files to demonstrate it:
cpp_custom_allocator.h:
cpp_custom_allocator.cpp:
cpp_custom_allocator.d:
It can be tested with:
The output is:
In the first case it deletes from C++ and
C::operator deleteis called. In the second case it deletes from D usingcpp_deleteandC::operator deleteis not called.Fixing this would currently break freeing C++ classes allocated in D, because they don't have a real deleting destructor, see issue #23458.