当它是 noop 时是否需要调用一个非平凡的析构函数?

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

当您知道在这种特定情况下析构函数是 noop 时,标准是否要求调用非平凡的析构函数?

如果不调用析构函数,代码是否可能被编译器破坏?

用例是一个包含动态分配指针的 class。默认情况下,此指针由构造函数中的 new 获取。 this class 也可以从分配器中获取其动态分配的指针。 class 跟踪它是如何获得它的指针并在析构函数中调用 delete 如果指针是由 new 获得的,如果它是由分配器获得的则什么都不调用,因为分配器将释放记忆。存储在动态内存中的数据只是普通类型,因此不需要调用它们的析构函数。

所以问题是,如果我知道 class 是通过分配器获得其指针的,那么我还需要调用析构函数吗?

这是一个最小的简化示例,所有与问题不直接相关的内容都已删除。

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();
}

没有

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]

您不依赖于 ~C 的任何 side-effects,因此您没有未定义的行为。

N.B。你可能应该放置 new[] 你的 A.Allocate'd int[10]

C(Allocator& A) {
    ptr = new (A.Allocate(10 * sizeof(int))) int[10];
    need_cleanup = false;
}