Какой смысл удалить конструктор класса по умолчанию?

Я готовлюсь к экзамену CPP, и один из вопросов: вы можете удалить конструктор класса по умолчанию, и если да, то в чем причина? Хорошо, так что, очевидно, вы можете это сделать:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};

но я не понимаю, зачем вам это делать?

Ответ 1

Рассмотрим следующий класс:

struct Foo {
    int i;
};

Этот класс является агрегатом, и вы можете создать экземпляр со всеми тремя этими определениями:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}

Теперь скажем, что вам не нравятся неинициализированные значения и неопределенное поведение, которое они могут произвести. Вы можете удалить конструктор по умолчанию Foo:

struct Foo {
    Foo() = delete;
    int i;
};

Foo по-прежнему является совокупностью, но только последние два определения действительны - первая из них теперь является ошибкой времени компиляции.

Ответ 2

Существует несколько причин удалить конструктор по умолчанию.

  1. Класс является чисто статическим, и вы не хотите, чтобы пользователи создавали экземпляр класса только с помощью статических методов/членов. Примером такого класса может быть тот, который реализует шаблон фабричного проектирования, используя только статические методы для создания новых классов.
  2. Для класса не имело бы конструктора по умолчанию (поскольку для него требуются параметры/Нет значений по умолчанию, которые имели бы смысл для класса). В этом случае значение = delete - это стиль, как сказал @HolyBlackCat, но он проясняет ваше намерение, сообщая клиентскому коду только вызвать конструктор с параметрами.
  3. Вам не нужны неинициализированные данные для совокупного класса.

Если второе утверждение было неясным, рассмотрим следующий пример:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};

Если вы попытались вызвать конструктор по умолчанию прямо сейчас, вы получите ошибку, которая будет выглядеть примерно так (GCC 7.2):

error: нет подходящей функции для вызова "A :: A()"

Однако, если вы раскомментировали строку с помощью = delete, вы получите следующее:

Ошибка: использование удаленной функции "A :: A()"

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

Ответ 3

Множественный выбор по умолчанию

Удаление конструктора по умолчанию для класса является хорошей идеей, когда есть несколько вариантов для состояния по умолчанию или неинициализированного. Например, предположим, что у меня есть класс,

template<typename F>
class Polynomial;

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


Нет выбора по умолчанию

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

Что такое Manifold()? Это пустое пространство, без ничего, без поверхности, без понятия расстояния или метрики. Но тогда нет смысла думать об этом как о многообразии, а скорее о чем-то более общем, как о топологическом пространстве.

Таким образом, в этом случае я также хотел бы удалить конструктор по умолчанию.

Ответ 4

Иногда классы не предназначены для создания экземпляров.

Одним из примеров, которые до сих пор не были упомянуты, являются классы "признаков". Например, рассмотрим std::char_traits, хотя в стандарте не сказано, что его конструктор по умолчанию нужно удалить, его конструктор по умолчанию малопригодно, поскольку сам класс пуст, все его функции статичны и не нужны который должен быть создан для использования псевдонимов типов, которые он предоставляет.

Обычно классы признаков обычно используются только для поддержки других классов (обычно других классов шаблонов), поэтому часто бывает целесообразно удалить свой конструктор по умолчанию - чтобы укрепить представление о том, что они всего лишь вспомогательный тип и на самом деле не предполагается использовать как объект.