Значение = delete после объявления функции

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

Что означает = delete в этом контексте?

Существуют ли другие "модификаторы" (кроме = 0 и = delete)?

Ответ 1

Удаление функции функция С++ 11:

Теперь может быть выражена общая идиома "запрещение копирования" непосредственно:

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

[...]

Механизм "delete" может использоваться для любой функции. Например, мы может устранить нежелательное преобразование следующим образом:

struct Z {
    // ...

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

Ответ 2

  • = 0 означает, что функция является чистой виртуальной, и вы не можете создать объект из этого класса. Вы должны извлечь из него и реализовать этот метод.
  • = delete означает, что компилятор не будет генерировать эти конструкторы для вас. AFAIK это разрешено только для оператора копирования и оператора присваивания. Но я не слишком хорошо разбираюсь в предстоящем стандарте.

Ответ 3

Эта выдержка из языка программирования С++ [4-е издание] - книга Бьярна Страуструпа рассказывает о реальной цели за помощью =delete:

Использование копии по умолчанию или перемещения для класса в иерархии обычно a катастрофа: данный только указатель на базу, мы просто не знаем, что члены производного класса имеют (§3.2.2), поэтому мы не можем знать, как копировать их. Итак, лучше всего, чтобы удалить копию по умолчанию и перемещать операции, то есть устранять определения по умолчанию эти две операции:

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

= delete - это функция, введенная в С++ 11. По =delete ему не разрешается вызывать эту функцию.

Подробнее.

Предположим, что в классе.

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

  }
};

При вызове этой функции для назначения obj это не будет разрешено. Оператор присваивания событий будет ограничивать копирование с одного объекта на другой.

Ответ 6

Стандарты кодирования, с которыми я работал, были следующими для большинства объявлений классов.

//  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;

Ответ 8

Это новая вещь в стандартах С++ 0x, где вы можете удалить унаследованную функцию.

Ответ 9

Удаленная функция неявно встроена

(Приложение к существующим ответам)

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

Цитируя [dcl.fct.def.delete]/4:

Удаленная функция неявно встроена. (Примечание: правило одного определения ([basic.def.odr]) применяется к удаленным определениям. - примечание конца] Удаленное определение функции должно быть первым объявлением функции или, для явной специализации шаблона функции. первое объявление этой специализации. [Пример:

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

- конец примера)

Шаблон основной функции с удаленным определением может быть специализированным

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

До концепции удаленной функции С++ 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; */
}