Следует ли никогда не использовать определяемый пользователем пустой деструктор?

struct A1
{
    ~A1() {} // A1 is not trivially destructible
};

struct A2
{
    ~A2() = default; // A2 is trivially destructible
};

A2 лучше, чем A1, потому что A2 легко разрушить, а A1 — нет.

Я думаю, может быть, мы можем с уверенностью сказать:

1. Пользовательский пустой деструктор никогда не должен использоваться.

2. Любой определяемый пользователем пустой деструктор следует заменить деструктором по умолчанию.

Я прав?


person xmllmx    schedule 18.04.2021    source источник
comment
Связано: stackoverflow.com/questions/28909598/   -  person πάντα ῥεῖ    schedule 18.04.2021
comment
Я бы поспорил с 2, что любой определяемый пользователем пустой деструктор должен быть удален. Если вам не нужно оставить его по умолчанию для целей самодокументирования.   -  person Yksisarvinen    schedule 18.04.2021
comment
Я согласен, см.: isocpp.github.io/CppCoreGuidelines/   -  person Roxxorfreak    schedule 18.04.2021
comment
@Yksisarvinen В основных рекомендациях говорится: если деструктора по умолчанию достаточно, используйте его. Так что я бы сказал: да, заменить.   -  person Roxxorfreak    schedule 18.04.2021
comment
t@Roxxorfreak Похоже, что по умолчанию здесь подразумевается неявное. Первое предложение связанного правила гласит: «Нужен ли этому классу деструктор?» удивительно проницательный вопрос дизайна. Для большинства классов ответ «нет» либо потому, что класс не содержит ресурсов, либо потому, что уничтожение обрабатывается по правилу нуля. И правило нуля гласит: >Если вы можете избежать определения операций по умолчанию, сделайте   -  person Yksisarvinen    schedule 18.04.2021
comment
Здесь вы уже можете найти хорошее объяснение: по умолчанию отличается от конструктора и деструктора по умолчанию"> stackoverflow.com/questions/13576055/   -  person Dirk Hönisch    schedule 18.04.2021
comment
Для меня единственный вариант использования пустого деструктора, с которым я столкнулся, - это virtual ~Base() {}, который может быть virtual ~Base() = default;. Но иногда вам нужно добавить Base::~Base() = default; в реализующий файл Base.cpp, чтобы компилятор мог сгенерировать виртуальную таблицу.   -  person Eljay    schedule 18.04.2021
comment
fluentcpp.com/2017/09/22/make-pimpl -using-unique_ptr по уважительной причине   -  person Matt Eding    schedule 18.04.2021


Ответы (2)


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

Впрочем, вы недалеко от цели. За десятилетие программирования на C++ я каждый день видел множество пустых деструкторов, но ни одного, который нельзя было бы заменить на =default или вообще исключить.

Тем не менее, я бы с осторожностью относился к механической замене. Так:

  1. Определяемый пользователем пустой деструктор почти никогда не должен использоваться.

  2. Почти каждый определяемый пользователем пустой деструктор следует либо полностью исключить (предпочтительный вариант), либо заменить деструктором по умолчанию.

person besc    schedule 18.04.2021

В заголовочном файле:

struct some_secret_type;
struct some_public_type {
  some_public_type();
  ~some_public_type();
private:
  std::unique_ptr<some_secret_type> pImpl;
};

Затем в файле cpp:

#include <some_secret_type.h>

some_public_type::~some_public_type() = default;
some_public_type::~some_public_type() {};

Здесь я явно объявил деструктор, который оказался либо пустым, либо дефолтным.

Эффекты =default; и {} здесь идентичны в файле cpp.

В заголовочном файле наличие {} или =default потребует, чтобы все, включая его, знали, как выглядит some_secret_type.

В более общем случае {} и =default в заголовке могут измениться, если тип тривиально уничтожен. В разделении cpp/header их нет.

Преимущество {} в заголовке состоит в том, что вы не допускаете, чтобы тип был тривиальным (предположим, позже вы знаете, что собираетесь сделать его нетривиальным, и вы не хотите, чтобы при этом происходили другие изменения поведения).

В случае файла cpp {} экономит несколько символов.

person Yakk - Adam Nevraumont    schedule 18.04.2021