C++ 禁用复制和移动语义的最简洁方法

C++ 禁用复制和移动语义的最简洁方法,c++,c++11,copy,move-semantics,C++,C++11,Copy,Move Semantics,以下内容当然有效,但非常乏味: 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

以下内容当然有效,但非常乏味:

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&&)
,因为它可以同时用于这两个目的。

根据这张图表(由Howard Hinnant编写):

最简洁的方法是
=delete
移动赋值运算符(或移动构造函数,但可能会导致注释中提到的问题)


不过,在我看来,最具可读性的方法是删除复制构造函数和复制赋值运算符。

您可以编写一个简单的
结构
,并从中继承:

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
}
我更喜欢从中继承,从而使意图立即明确,并将细节委托给一个值得信赖的库

#include <boost/core/noncopyable.hpp>

class X: private boost::noncopyable
{
};
#包括
X类:私有boost::不可复制
{
};
它涉及到添加依赖项,但如果您对此没有异议,那么这可以说是一种非常简洁且富有表现力的方法。

请不要试图找到“最简洁的方法”来编写代码。 如果没有一种简单明了的表达方式,那就不要去寻找,也不要试图用你自己的方式少写几个字。为什么?想想人们阅读你的代码:如果你需要参考标准来实现你的代码做你想做的事情,那么你的代码的读者也会这么做。除了他们不知道你想要达到什么;所以他们不会参考标准;所以他们只会对你的代码的功能感到困惑。或者——有些人会得到,有些人不会*

在你的例子中,如果你做了这些删除的一个子集,或者使用了其他一些“聪明”的技巧——作为一个阅读你的代码的人,我可能不会理解,不会注意到你实际上试图删除所有的复制和移动语义。我会感到困惑,以为你在做别的事。事实上,如果我是你,我甚至会考虑添加一个评论:

/* 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++ Howard Hinnant已经着手解决这个问题了。
*-一种基于我所阐述的原理的变体。

我认为在这种情况下,宏实际上更具可读性:

#define NOT_COPYABLE( TypeName ) \
TypeName ( TypeName const& ) = delete; \
TypeName & operator = ( TypeName const& ) = delete;

#define NOT_MOVEABLE( TypeName ) \
TypeName ( TypeName && ) = delete; \
TypeName & operator = ( TypeName && ) = delete;

否。使用4行版本显式禁用所有4行。基类如何?在标准中,最好删除复制构造函数和复制赋值运算符。比较。
boost::noncopyable
是一种简洁而富有表现力的方法,如果你不介意为依赖项付费(或者已经有了依赖项)@ricab我从C++11开始就有点厌倦boost了,因为它承诺与C++03向后兼容。我还建议只使用赋值操作符,而不推荐移动操作符。显式删除c'tor可能会搞乱RVO@Lingxi-不会影响其他特殊成员函数的生成。例如,你仍然会得到一个复制/移动任务;这些都是标准设计中的缺陷,也是一个问题。我的指导方针是,我相信Boost有这样一个类。继承它而不是滚动您自己的(虽然如果这是唯一的用途,那么在项目中使用Boost就不值得了)。这将是Boost::noncopyable(),您假设最简洁的方式表达性较差,但事实并非如此。如果能在保持精确性的同时简洁地表达意图,意图就会更清楚。@ricab:请参见编辑。关键是,“最简洁”不是一种美德。我坚持认为,如果它不违背表达的话,它就是一种美德
boost::noncopyable
是实现这两个目标的一个很好的例子