Skip to content

cpp_delete does not use class specific C++ operator delete #23509

Description

@tim-dlang

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions