Наиболее сжатый способ отключения копирования и перемещения семантики
Следующее, безусловно, работает, но очень утомительно:
T(const T&) = delete;
T(T&&) = delete;
T& operator=(const T&) = delete;
T& operator=(T&&) = delete;
Я пытаюсь найти наиболее сжатый способ. Будут ли следующие работы?
T& operator=(T) = delete;
Обновление
Обратите внимание, что я выбираю T& operator=(T)
вместо T& operator=(const T&)
или T& operator=(T&&)
, потому что он может служить обеим целям.
Ответы
Ответ 1
Согласно этой диаграмме (Howard Hinnant):
![meow]()
Наиболее кратким способом является =delete
переместить оператор присваивания (или переместить конструктор, но это может вызвать проблемы, упомянутые в комментариях).
Хотя, на мой взгляд, наиболее читаемым способом является =delete
как конструктор копирования, так и оператор копирования.
Ответ 2
Пожалуйста, не пытайтесь найти "самый лаконичный способ" написать кусок кода.
Если нет очевидной формы выражения чего-то, что также является очень лаконичным - не ищите, не пытайтесь объяснить языком юриста свой путь к написанию на несколько символов меньше. Зачем? Подумайте о людях, читающих ваш код: если вам нужно обратиться к стандарту, чтобы понять, что ваш код выполняет то, что вы хотите, то и ваши читатели кода тоже. За исключением того, что они не будут знать, чего вы пытаетесь достичь; поэтому они не будут консультироваться со стандартом; так что они просто будут смущены тем, что делает ваш код. Или - некоторые получат это, а некоторые не будут. * 1
В вашем случае, если вы сделаете подмножество этих удалений или воспользуетесь каким-то другим "умным" приемом - как человек, читающий ваш код, скорее всего, я не поймаю вас, не заметив, что вы на самом деле пытаетесь получить все копии и семантика перемещения удалена. И я запутаюсь, думая, что вы пытаетесь сделать что-то еще. На самом деле, на вашем месте я бы даже подумал добавить комментарий:
/* Disabling copy and move semantics because XYZ */
T(const T&) = delete;
T(T&&) = delete;
T& operator=(const T&) = delete;
T& operator=(T&&) = delete;
что еще более "утомительно", но сделает ваши намерения/мотивы абсолютно ясными для ваших будущих читателей.
Там также вопрос о том, что именно причина "XYZ". Некоторые утверждают, что нет веских причин для удаления участников перемещения, и, как правило, это плохая идея. C++ светило Говард Хиннант говорит об этом.
* - вариант по принципу, который я изложил здесь.
Ответ 3
Я предпочитаю наследовать от boost:: noncopyable, тем самым делая намерение незамедлительно понятным и делегируя детали в надежную библиотеку.
#include <boost/core/noncopyable.hpp>
class X: private boost::noncopyable
{
};
Он включает в себя добавление зависимости, но если вы в порядке с этим, это, возможно, очень сжатый и выразительный способ выполнить его.
Ответ 4
Вы можете написать простой struct
и наследовать от него:
struct crippled
{
crippled() = default;
crippled(const crippled&) = delete;
crippled(crippled&&) = delete;
crippled& operator=(const crippled&) = delete;
crippled& operator=(crippled&&) = delete;
};
Использование:
struct my_class : crippled
{
};
int main()
{
my_class a;
auto b = a; // fails to compile
}
Ответ 5
Я считаю, что в этом случае макросы на самом деле более читабельны:
#define NOT_COPYABLE( TypeName ) \
TypeName ( TypeName const& ) = delete; \
TypeName & operator = ( TypeName const& ) = delete;
#define NOT_MOVEABLE( TypeName ) \
TypeName ( TypeName && ) = delete; \
TypeName & operator = ( TypeName && ) = delete;