Я хочу, чтобы некоторые классы использовали автоматически сгенерированные конструкторы, но не подлежали копированию (но все еще могли быть перемещены). В настоящее время я делаю это так:
class A
{
public:
A() = default;
A(const A&) = delete;
A(A&&) = default;
A& operator=(const A&) = delete;
A& operator=(A&&) = default;
}
Интересно, действительно ли нужно быть таким явным? Что делать, если я написал это так:
class A
{
A(const A&) = delete;
A& operator=(const A&) = delete;
}
Будет ли это работать так же? Каков минимальный набор значений по умолчанию и удалений для других случаев — не копируемого неподвижного класса и класса с виртуальным деструктором?
Есть ли тестовый код, который я могу использовать, чтобы быстро увидеть, какие конструкторы неявно созданы?
Это не будет работать, потому что конструктор по умолчанию не будет создан для вас автоматически. Конструктор по умолчанию не будет создан, потому что вы объявили конструктор копирования. Он определен как удаленный, но, тем не менее, он объявлен пользователем, поэтому не существует неявно используемого по умолчанию конструктора по умолчанию.
Сокращенные правила для неявно созданных конструкторов:
Есть ли тестовый код, который я могу использовать, чтобы быстро увидеть, какие конструкторы
неявно создано?
Да. Например:
#include <type_traits>
class A
{
public:
A() = default;
A(A&&) = default;
A& operator=(A&&) = default;
};
static_assert(std::is_nothrow_default_constructible<A>::value,
"A must be noexcept default constructible");
static_assert(std::is_nothrow_destructible<A>::value,
"A must be noexcept destructible");
static_assert(!std::is_copy_constructible<A>::value,
"A must not be copy constructible");
static_assert(!std::is_copy_assignable<A>::value,
"A must not be copy assignable");
static_assert(std::is_nothrow_move_constructible<A>::value,
"A must be noexcept move constructible");
static_assert(std::is_nothrow_move_assignable<A>::value,
"A must be noexcept move assignable");
Выше я использовал _nothrow_
в некоторых чертах. Удалите эту часть, если вы хотите разрешить ассоциированному специальному члену генерировать исключение.
Я бы посоветовал вам редко делать это. И в тех немногих случаях, когда вам нужно это сделать, явное объявление о том, какие специальные функции удалены, а какие — по умолчанию, может быть неплохим.
Обычная причина, по которой вам может потребоваться явно определить или удалить специальные функции-члены, заключается в том, что ваш класс является своего рода классом управления ресурсами. Например, у него есть указатели-владельцы, и компилятор не знает, кто является владельцем этого ресурса. Однако, как описано в Правило нуля статья:
C ++ позволяет нам инкапсулировать политики владения в универсальные многоразовые
классы. Это важный бит! Чаще всего наши потребности в собственности
может обслуживаться классами «владение в пакете».Общие классы «владение в пакете» включены в стандарт
библиотека: std :: unique_ptr и std :: shared_ptr. Благодаря использованию
настраиваемые объекты удаления, оба были сделаны достаточно гибкими, чтобы управлять
практически любой вид ресурса.
Поэтому нам очень редко приходится писать собственный класс управления ресурсами. Обычно должно быть возможно создать класс из других классов, в которых уже есть владелец. И тогда специальные функции-члены по умолчанию должны быть такими, как вы ожидаете.
Например, если у вас есть std::unique_ptr
член тогда ваш класс неявно не копируемый или если у вас есть const
член, то ваш класс неявно не назначается.
Тем не менее, если вам нужно явно сделать класс не копируемым, @ N.m. вкратце изложены правила, когда неявно определяются конструкторы / операторы присваивания и так нужно как минимум
A() = default;
A(A&&) = default;
A& operator=(A&&) = default;
И я согласен с вами в том, что C ++ 11 достаточно выразителен, и нам больше не нужен импульс для этого.
Вы можете избежать определения удаленной копии c’or и оператора присваивания, используя
повысить не копируемый
таким образом, намерение может быть даже более явным и ясным, чем использование ключевого слова «delete»
Вы можете просто использовать это как:
#include <boost/utility.hpp>
class A : boost::noncopyable {
public:
A () = default;
A (A&&) = default;
A& operator= (A&&) = default;
};