Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it required to call a non-trivial destructor when it is a noop?

is it required by the standard to call non-trivial destructor when you know that in this specific case the destructor is a noop ?

is the code likely to be broken by compliers if the destructor is not called ?

the use case is a class that contain a dynamicly allocated pointer. by default this pointer is obtained by new in the constructor. this class can also get its dynamicly allocated pointer from an allocator. the class keeps track of how it obtained its pointer and calls delete in the destrucor if the pointer was obtained by new and nothing if it was obtained by the allocator because the allocator will free the memory. the data stored in the dynamic memory is only trivial type so their destructor doesn't need to be called.

so the question is do i still need to call the destructor on the class if i know that it obtained its pointer via the allocator so the destructor is a noop ?

this is a minimal simplified example everything not directly related to the issue was removed.

struct Allocator {
    void* ptr = nullptr;
    void* Allocate(size_t size) {
        ptr = malloc(size);
        return ptr;
    }
    ~Allocator() { // allocator will cleanup
        if (ptr)
            free(ptr);
    }
};

struct C {
    int* ptr;
    bool need_cleanup;
    C() {
        ptr = new int[10];
        need_cleanup = true;
    }
    C(Allocator& A) {
        ptr = (int*)A.Allocate(10 * sizeof(int));
        need_cleanup = false;
    }
    ~C() { // non-triviall because user-defined.
        if (need_cleanup)
            delete[] ptr;
        // noop if need_cleanup is false.
    }
};

int main()
{
    Allocator A;
    alignas(C) char buffer[sizeof(C)];
    C* c = new(buffer) C(A);
    /// is it required to call c->~C();
}
like image 269
Tyker Avatar asked Jun 12 '19 10:06

Tyker


People also ask

Is there a non-trivial destructor?

A class has a non-trivial destructor if it either has an explicitly defined destructor, or if it has a member object or a base class that has a non-trivial destructor.

Do destructors need to be called?

No. You never need to explicitly call a destructor (except with placement new ). A class's destructor (whether or not you explicitly define one) automagically invokes the destructors for member objects. They are destroyed in the reverse order they appear within the declaration for the class.

What happens if destructor is not called?

A destructor has the same name as the class, preceded by a tilde ( ~ ). For example, the destructor for class String is declared: ~String() . If you do not define a destructor, the compiler will provide a default one; for many classes this is sufficient.

Are destructors automatically called?

Destructor neither requires any argument nor returns any value. It is automatically called when object goes out of scope. Destructor release memory space occupied by the objects created by constructor. In destructor, objects are destroyed in the reverse of an object creation.


1 Answers

No.

For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression ([expr.delete]) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

[basic.life]

You are not depending on any side-effects of ~C, so you don't have undefined behavior.

N.B. you should probably placement new[] your A.Allocate'd int[10]

C(Allocator& A) {
    ptr = new (A.Allocate(10 * sizeof(int))) int[10];
    need_cleanup = false;
}
like image 57
Caleth Avatar answered Dec 20 '22 12:12

Caleth