навіщо явно видаляти конструктор?


94

Коли / чому я хочу явно видалити свій конструктор? Якщо припустити, що причина полягає у тому, щоб запобігти його використанню, чому б просто не зробити це private?

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

14
Це якось добре поєднується = default, навіть клас не може цим користуватися, і я особисто вважаю за краще бачити Використання видаленої функції. over Функція є приватною. Перший прямо заявляє: "Це не призначено для використання". Якщо що-небудь виходить із цього, клас, який не може його використовувати, насправді має семантичну різницю.
chris

16
Я щиро думаю, що люди починають агресивно ставитися до голосування. Я не розумію, як це не конструктивно.
Luchian Grigore

4
@LuchianGrigore: Погоджено. Я дивувався, чому я сам став набагато жорсткішим. Я не бачу сенсу.
Ed S.

11
Оскільки я рідко використовую C ++ 11, це для мене більш інформативно, ніж OP, мабуть, навіть усвідомлює. Я навіть не знав, що ви можете позначити конструктор delete. І питання, і відповідь Лучіана легко кваліфікуються як конструктивні. Той, хто не дихає кращими точками C ++ 11, але повинен буде незабаром, отримає щось із обох.
WhozCraig

Відповіді:


88

Як на рахунок:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

проти

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

Це в основному різні речі. privateговорить вам, що лише члени класу можуть викликати цей метод або отримувати доступ до цієї змінної (або, звичайно, друзі). У цьому випадку законним для staticметоду цього класу (або будь-якого іншого члена) є виклик privateконструктора класу. Це не стосується видалених конструкторів.

Зразок тут .


3
Вам не потрібно оголошувати Foo () взагалі, якщо ви оголошуєте Foo (int). Foo () не буде генеровано, і тому Foo f у будь-якому випадку недійсний. Отже, ваш приклад не показує випадок видаленого конструктора. Переконайтесь самі - ideone.com/mogiIF
позначте

1
@mark Я написав 2 конструктори, щоб довести це. Редагуватиму, щоб було зрозуміло всім.
Luchian Grigore

1
Я розумію різницю, я просто не розумію додану вартість оператора delete загалом і для конструктора зокрема. Зрештою, я міг би вказати приватний конструктор за замовчуванням без тіла. Тоді код також виходить з ладу, лише під час посилання. Ну, я бачу, що видалення передає намір більш чітко, але це все.
позначка

11
@mark Так, це був би спосіб робити C ++ 98. Але IMHO, чітка передача наміру насправді є дуже важливою річчю у програмуванні загалом. У цьому випадку деякі читачі можуть побачити приватний невизначений конструктор і припустити, що він випадковий, і просто додати для нього визначення, особливо якщо визначення таке ж тривіальне, як конструктор за замовчуванням (Так, наявність коментаря допомагає, але ми набагато віддамо перевагу компілятору -застосування над зауваженням). Отримавши чіткіші наміри, ми також отримуємо набагато краще повідомлення про помилку, яке говорить "явно видалено", а не "невизначене посилання".
mpark

2
Я, чесно кажучи, не розумію, як це відповідає на головне питання. Питання в заголовку та перше запитання OP у дописі було: Коли / чому я хочу явно видалити свій конструктор?
Олександр Болінський

12

навіщо явно видаляти конструктор?

Ще одна причина:
я використовую, deleteколи хочу запевнити, що клас викликається за допомогою ініціалізатора. Я вважаю це дуже елегантним способом досягти цього без перевірок виконання.

Компілятор С ++ робить цю перевірку за вас.

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

Цей - дуже спрощений - код гарантує, що такого екземпляра не існує:Foo foo;


12
Видалена декларація тут непотрібна. Він автоматично видаляється будь-яким наданим користувачем конструктором
Mike Lui

5
Щоб пояснити коментар @MikeLui, видалена декларація непотрібна компілятору . Існує безліч випадків, коли подібний код слід включати, щоб заявити про намір іншим програмістам .
Jeff G

Разом із заявою про ваш намір, це створює очевидне місце для документування вашої причини її видалення в загальнодоступному інтерфейсі, а крім того, помилка компілятора буде короткою, наприклад, "використання видаленої функції". Якби в ньому Fooбуло багато конструкторів, а не за замовчуванням, то Foo foo;це призвело б до набагато довшої помилки з переліком усіх неявно визначених, захищених та приватних конструкторів, яким не вдалося збігтися.
сигма

Я все ще не розумію, як зайвий рядок із оголошенням конструктора, яке ключове слово "= delete", декларує намір ідеї "немає конструктора за замовчуванням" краще, ніж ... просто немає конструктора за замовчуванням? Зразок: Я не хочу оголошувати змінну "a" у своєму коді - що краще, писати "// int a; // не потрібно визначати змінну a" або просто нічого не писати про цю змінну в коді?
Еж

2

Я зустрічався з типовими ctors, оголошеними як "видалені" у вихідному коді LLVM (наприклад, у AlignOf.h). Зв’язані шаблони класів, як правило, знаходяться у спеціальному просторі імен, який називається 'llvm :: detail'. Вся ціль там, я думаю, полягала в тому, що вони розглядали цей клас лише як допоміжний клас. Вони ніколи не мали наміру робити їх екземплярами; лише для використання їх у контексті інших шаблонів класів з деякими прийомами метапрограмування, які виконуються під час компіляції.

Напр. є цей шаблон класу AlignmentCalcImpl, який використовується лише в іншому шаблоні класу, який називається AlignOf, як параметр для оператора sizeof (.). Цей вираз можна оцінити під час компіляції; і немає необхідності створювати екземпляр шаблону -> так чому б не оголосити ctor за замовчуванням delete для вираження цього наміру.

Але це лише моє припущення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.