Значення = видалити після оголошення функції


242
class my_class
{
    ...
    my_class(my_class const &) = delete;
    ...
};

Що = deleteозначає в цьому контексті?

Чи є інші "модифікатори" (крім = 0та = delete)?


23
@Blindy Це буде стандартно в C ++ 0x, тобто незабаром.
Конрад Рудольф

1
Я виправлений, я пропустив цю функцію C ++ 0x. Я думав, що це #definea la Qt, яке оцінюється на 0, а потім оголошує приховану функцію чи щось таке.
Сліпий

У мене є згадування ключового слова "відключити", що означає те саме або щось подібне. Я це уявляю? Або між ними є тонка різниця?
Стюарт

Відповіді:


201

Видалення функції - це функція C ++ 11 :

Загальна ідіома "забороняти копіювання" тепер може бути виражена безпосередньо:

class X {
    // ...
    X& operator=(const X&) = delete;  // Disallow copying
    X(const X&) = delete;
};

[...]

Механізм "видалити" можна використовувати для будь-якої функції. Наприклад, ми можемо усунути небажане перетворення на зразок цього:

struct Z {
    // ...

    Z(long long);     // can initialize with an long long         
    Z(long) = delete; // but not anything less
};

3
Хіба не традиційний метод "заборонити копіювання" просто для того, щоб зробити copy-ctor і operator = "приватним?" Це піде трохи далі і вказує компілятору навіть не генерувати функції. Якщо вони приватні і = видаляють, чи заборонено копіювання подвійно?
Reb.Cabin

8
@Reb, =deleteробить метод недоступним навіть із контекстів, які можуть бачити privateметоди (тобто в межах класу та його друзів). Це знімає будь-яку непевність під час читання коду. @Prasoon, цей другий приклад все ще лише видаляє конструктори - було б непогано бачити, operator long ()наприклад, видалений .
Toby Speight

2
@ Reb.Cabin Використовувати = deleteкраще, ніж використовувати privateчи інші подібні механізми, тому що зазвичай ви хочете, щоб заборонена функція була видимо оголошена і розглянута для вирішення перевантаження і т.д., щоб вона могла вийти з ладу якомога раніше і забезпечити явнішу помилку користувачеві. Будь-яке рішення, що включає "приховування" декларації, зменшує цей ефект.
Левшенко

1
Чи є особлива причина оприлюднити конструктор копій і застосувати ключове слово видалення. Чому б не залишити конструктор приватним і застосувати ключове слово?
Dohn Joe

81
  1. = 0означає, що функція є чисто віртуальною, і ви не можете створити об'єкт із цього класу. Вам потрібно вийти з цього і реалізувати цей метод
  2. = deleteозначає, що компілятор не буде генерувати ці конструктори для вас. AFAIK це дозволено лише в конструкторі копій та операторі призначення. Але я не надто хороший у майбутньому стандарті.

4
Є деякі інші способи використання =deleteсинтаксису. Наприклад, ви можете використовувати його, щоб явно заборонити якісь неявні перетворення, які можуть відбуватися під час виклику. Для цього ви просто видалите перевантажені функції. Перегляньте сторінку Вікіпедії на C ++ 0x для отримання додаткової інформації.
LiKao

Я зроблю це, як тільки знайду його. Вгадайте, що пора наздогнати c ++ 0X
mkaes

Так, С ++ 0х порід. Я не можу чекати, коли GCC 4.5+ стане більш поширеним, тому я можу почати використовувати лямбда.
LiKao

5
Опис для = deleteне зовсім коректний. = deleteможе використовуватися для будь-якої функції, в цьому випадку вона явно позначена як видалена, а будь-яке використання призводить до помилки компілятора. Для спеціальних функцій-членів це також означає, зокрема, що вони потім не створюються для вас компілятором, але це лише результат видалення, а не те, що = deleteє насправді.
MicroVirus

28

Цей уривок із мови програмування на C ++ [4-е видання] - Книга Б'ярн Струструп розповідає про реальну мету використання =delete:

3.3.4 Придушення операцій

Використання за замовчуванням копії або переміщення для класу в ієрархії, як правило, є катастрофою : даючи лише вказівник на базу, ми просто не знаємо, якими членами є похідний клас, тому ми не можемо знати, як їх скопіювати . Отже, найкраще робити, як правило, видалити операції копіювання та переміщення за замовчуванням, тобто усунути визначення за замовчуванням цих двох операцій:

class Shape {
public:
  Shape(const Shape&) =delete; // no copy operations
  Shape& operator=(const Shape&) =delete;

  Shape(Shape&&) =delete; // no move operations
  Shape& operator=(Shape&&) =delete;
  ˜Shape();
    // ...
};

Тепер спроба скопіювати форму буде спіймана компілятором.

=deleteМеханізм носить загальний характер , тобто, він може бути використаний для придушення будь-якої операції



5

Стандарти кодування, з якими я працював, мали більшість декларацій класу.

//  coding standard: disallow when not used
T(void)                  = delete; // default ctor    (1)
~T(void)                 = delete; // default dtor    (2)
T(const T&)              = delete; // copy ctor       (3)
T(const T&&)             = delete; // move ctor       (4)
T& operator= (const T&)  = delete; // copy assignment (5)
T& operator= (const T&&) = delete; // move assignment (6)

Якщо ви використовуєте будь-який із цих 6, ви просто прокоментуєте відповідний рядок.

Приклад: для класу FizzBus потрібен лише dtor, тому інші 5 не використовуються.

//  coding standard: disallow when not used
FizzBuzz(void)                         = delete; // default ctor (1)
// ~FizzBuzz(void);                              // dtor         (2)
FizzBuzz(const FizzBuzz&)              = delete; // copy ctor    (3)
FizzBuzz& operator= (const FizzBuzz&)  = delete; // copy assig   (4)
FizzBuzz(const FizzBuzz&&)             = delete; // move ctor    (5)
FizzBuzz& operator= (const FizzBuzz&&) = delete; // move assign  (6)

Ми коментуємо тут лише 1, а інсталюємо реалізацію його ще де (можливо, там, де підказує стандарт кодування). Інші 5 (з 6) заборонено видаляти.

Ви також можете використовувати "= delete", щоб заборонити неявну рекламу різного розміру значень ... приклад

// disallow implicit promotions 
template <class T> operator T(void)              = delete;
template <class T> Vuint64& operator=  (const T) = delete;
template <class T> Vuint64& operator|= (const T) = delete;
template <class T> Vuint64& operator&= (const T) = delete;

3

= deleteце введення функції в C ++ 11. Відповідно =deleteдо цієї функції не дозволяється викликати цю функцію.

Детально.

Припустимо, у класі.

Class ABC{
 Int d;
 Public:
  ABC& operator= (const ABC& obj) =delete
  {

  }
};

Під час виклику цієї функції для призначення obj вона заборонена. Оператор призначання засобів обмежується копіювати з одного об'єкта на інший.


2

Новий стандарт C ++ 0x. Див. Розділ 8.4.3 робочого проекту N3242


Ого, цей проект застарілий. Ось останні (станом на 3 квітня 2011 року): open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
TonyK

Дякуємо та оновили посилання. Дуже корисно отримати поточний проект. Згаданий розділ / вміст був правильним навіть у старому проекті, тому я не розумію голосування проти.
dubnde

1

Видалена функція неявно вбудована

(Додаток до існуючих відповідей)

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

Посилаючись на [dcl.fct.def.delete] / 4 :

Видалена функція неявно вбудована. ( Примітка . Правило одного визначення ( [basic.def.odr] ) застосовується до видалених визначень. - кінцева примітка ] Видалене визначення функції є першим оголошенням функції або для явної спеціалізації шаблону функції , перша декларація цієї спеціалізації. [Приклад:

struct sometype {
  sometype();
};
sometype::sometype() = delete;      // ill-formed; not first declaration

- кінцевий приклад )

Шаблон основної функції із видаленим визначенням може бути спеціалізованим

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

Перед вилученою концепцією функції C ++ 11 можна було це зробити, просто опустивши визначення шаблону первинної функції, але це дало незрозумілі невизначені посилання помилки, які, можливо, не давали жодного смислового наміру від автора шаблону первинної функції (навмисно опущено ?). Якщо ми замість цього явно видалимо шаблон основного функціоналу, повідомлення про помилки, якщо не знайдена відповідна явна спеціалізація, стає набагато приємнішою, а також показує, що упущення / видалення визначення шаблону основної функції було навмисним.

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t);

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    //use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}

Однак, замість того, щоб просто опустити визначення шаблону основної функції вище, видаючи незрозумілу невизначену посилання, коли явна спеціалізація не збігається, визначення основного шаблону можна видалити:

#include <iostream>
#include <string>

template< typename T >
void use_only_explicit_specializations(T t) = delete;

template<>
void use_only_explicit_specializations<int>(int t) {
    std::cout << "int: " << t;
}

int main()
{
    const int num = 42;
    const std::string str = "foo";
    use_only_explicit_specializations(num);  // int: 42
    use_only_explicit_specializations(str);
    /* error: call to deleted function 'use_only_explicit_specializations' 
       note: candidate function [with T = std::__1::basic_string<char>] has 
       been explicitly deleted
       void use_only_explicit_specializations(T t) = delete; */
}

Подаючи більш читабельне повідомлення про помилку, де наміри видалення також добре видно (де невизначена помилка посилання може призвести до того, що розробник вважає це непродуманою помилкою).

Повертаючись до того, чому ми хотіли б коли-небудь використовувати цю техніку? Знову ж таки, явні спеціалізації можуть бути корисними для неявного усунення неявних перетворень.

#include <cstdint>
#include <iostream>

void warning_at_best(int8_t num) { 
    std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}

template< typename T >
void only_for_signed(T t) = delete;

template<>
void only_for_signed<int8_t>(int8_t t) {
    std::cout << "UB safe! 1 byte, " << +t << "\n";
}

template<>
void only_for_signed<int16_t>(int16_t t) {
    std::cout << "UB safe! 2 bytes, " << +t << "\n";
}

int main()
{
    const int8_t a = 42;
    const uint8_t b = 255U;
    const int16_t c = 255;
    const float d = 200.F;

    warning_at_best(a); // 42
    warning_at_best(b); // implementation-defined behaviour, no diagnostic required
    warning_at_best(c); // narrowing, -Wconstant-conversion warning
    warning_at_best(d); // undefined behaviour!

    only_for_signed(a);
    only_for_signed(c);

    //only_for_signed(b);  
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = unsigned char] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */

    //only_for_signed(d);
    /* error: call to deleted function 'only_for_signed' 
       note: candidate function [with T = float] 
             has been explicitly deleted
       void only_for_signed(T t) = delete; */
}

0

Це нова річ у стандартах C ++ 0x, де можна видалити успадковану функцію.


11
Ви можете видалити будь-яку функцію. Наприклад, void foo(int); template <class T> void foo(T) = delete;зупиняє всі неявні перетворення. intПриймаються лише аргументи типу, всі інші намагатимуться створити функцію "видалених".
UncleBens
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.