Обязательно ли вызывать нетривиальный деструктор, когда он noop? - PullRequest
4 голосов
/ 12 июня 2019

требуется ли в стандарте вызывать нетривиальный деструктор, когда вы знаете, что в данном конкретном случае деструктор является noop?

может ли код быть взломан компиляторами, если деструктор не вызван?

вариант использования - это класс, который содержит динамически размещенный указатель. по умолчанию этот указатель получается в конструкторе new. этот класс также может получить свой динамически распределенный указатель из распределителя. класс отслеживает, как он получил свой указатель, и вызывает деструктор delete, если указатель был получен с помощью new, и ничего, если он был получен распределителем, поскольку распределитель освободит память. данные, хранящиеся в динамической памяти, имеют только тривиальный тип, поэтому их деструктор вызывать не нужно.

поэтому вопрос в том, нужно ли мне вызывать деструктор в классе, если я знаю, что он получил свой указатель через распределитель, так что деструктор является noop?

это минимальный упрощенный пример, все, что не имеет прямого отношения к проблеме, было удалено.

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

1 Ответ

9 голосов
/ 12 июня 2019

Нет.

Для объекта типа класса с нетривиальным деструктором программе не требуется явно вызывать деструктор до повторного использования или освобождения хранилища, которое занимает объект;однако, если явного вызова деструктора нет или если delete-expression ([expr.delete]) не используется для освобождения хранилища, деструкторне должен вызываться неявно, и любая программа, зависящая от побочных эффектов, создаваемых деструктором, имеет неопределенное поведение.

[basic.life]

Вы не зависитена любые побочные эффекты ~C, поэтому у вас нет неопределенного поведения.

NB вам, вероятно, следует разместить new[] ваш A.Allocate 'd int[10]

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