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

Tyk*_*ker 4 c++ memory-management lifetime language-lawyer explicit-destructor-call

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();
}
Run Code Online (Sandbox Code Playgroud)

Cal*_*eth 9

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;
}
Run Code Online (Sandbox Code Playgroud)

  • C ++不是C。我会提醒您不要试图欺骗C ++不要做“无用的”事情,因为您可能会遇到不确定的行为。如果您改为让编译器执行工作,则生成的输出可能只是您想要的最小内容 (2认同)
  • @Tyker•如果确实不需要noop析构函数,请相信C ++优化器可以消除它。请勿尝试对其进行手动优化,因为其中的绳索位于UB坑上方。 (2认同)