boost :: noncopyable的优点是什么?
为了防止拷贝一个类,你可以很容易地声明一个私有拷贝的构造函数/赋值操作符。 但是你也可以inheritanceboost::noncopyable
。
在这种情况下使用boost有什么优点/缺点?
我没有看到文档的好处:
#include <boost/noncopyable.hpp> struct A : private boost::noncopyable { };
VS:
struct A { A(const A&) = delete; A& operator=(const A&) = delete; };
当添加移动types时,我甚至认为这些文档是误导性的。 下面的两个例子是不可复制的,尽pipe它们是可移动的:
#include <boost/noncopyable.hpp> struct A : private boost::noncopyable { A(A&&) = default; A& operator=(A&&) = default; };
VS:
struct A { A(A&&) = default; A& operator=(A&&) = default; };
在多inheritance的情况下,甚至可能会有空间的惩罚:
#include <boost/noncopyable.hpp> struct A : private boost::noncopyable { }; struct B : public A { B(); B(const B&); B& operator=(const B&); }; struct C : public A { }; struct D : public B, public C, private boost::noncopyable { }; #include <iostream> int main() { std::cout << sizeof(D) << '\n'; }
对我来说这打印出来:
3
但是,我认为这有优越的文档:
struct A { A(const A&) = delete; A& operator=(const A&) = delete; }; struct B : public A { B(); B(const B&); B& operator=(const B&); }; struct C : public A { C(const C&) = delete; C& operator=(const C&) = delete; }; struct D : public B, public C { D(const D&) = delete; D& operator=(const D&) = delete; }; #include <iostream> int main() { std::cout << sizeof(D) << '\n'; }
输出:
2
我发现声明我的复制操作要比boost::non_copyable
多次是否从boost::non_copyable
派生要容易得多,如果这会花费我。 特别是如果我不是完整的inheritance层次的作者。
它使意图清晰明了 ,否则必须查看类的定义,然后search与复制语义有关的声明,然后查找声明的访问说明符,以确定类是不可复制的。 其他通过编写需要启用复制语义的代码来发现它并查看编译错误的方法。
总结别人的话:
boost::noncopyable
比私有拷贝方法的优点 :
- 意图更加明确和描述性。 使用私人复制function是一个成语比不可复制的要花更长的时间。
- 这是更less的代码/less打字/less混乱/更less的空间(最简单的会意外提供一个实现)。
- 它在types的元数据中embedded了正确的含义,类似于C#属性。 您现在可以编写一个只接受不可复制对象的函数。
- 它可能会在构build过程的早期捕获错误。 错误将在编译时而不是链接时出现,如果类本身或者类的朋友正在进行错误的复制。
- (几乎与#4相同)防止类本身或类的朋友调用私有复制方法。
私有拷贝方法优于boost::noncopyable
优点 :
- 没有提升依赖
- boost :: noncopyable的意图更清晰。
- Boost :: noncopyable可防止类方法意外地使用私有拷贝构造函数。
- 更less的代码与boost :: noncopyable。
我不明白为什么没有人提到它,但是:
使用noncopyable
的,你只需要写一次类的名字。
没有, 五重复制 :一个'A类',两个禁用分配,两个禁用复制构造函数。
引用文档:
“处理这些问题的传统方法是声明私人拷贝构造函数和拷贝分配,然后logging为什么这样做,但是从非拷贝派生更简单更清晰,而且不需要额外的文档。
http://www.boost.org/libs/utility/utility.htm#Class_noncopyable
一个具体的优点(除了更清楚地expression你的意图之外)是,如果一个成员或朋友函数试图复制一个对象,错误将会在编译阶段而不是链接阶段被更早地捕获。 基类的构造函数/赋值不能在任何地方访问,给编译错误。
它还可以防止你意外地定义函数(即键入{}
而不是;
),这是一个很容易被忽视的小错误,但是这会允许成员和朋友制作对象的无效副本。
优点是你不必自己写一个私人拷贝构造函数和一个私人拷贝操作符,它不需要编写额外的文档就可以清楚地expression你的意图。
一个小缺点(特定于GCC)是,如果你使用g++ -Weffc++
编译你的程序,并且你的类包含指针,例如
class C : boost::noncopyable { public: C() : p(nullptr) {} private: int *p; };
海湾合作委员会不明白发生了什么事情:
警告:'C类'有指针数据成员[-Weffc ++]
警告:但不覆盖'C(常量S&)'[-Weffc ++]
警告:或'operator =(const C&)'[-Weffc ++]
虽然它不会抱怨:
#define DISALLOW_COPY_AND_ASSIGN(Class) \ Class(const Class &) = delete; \ Class &operator=(const Class &) = delete class C { public: C() : p(nullptr) {} DISALLOW_COPY_AND_ASSIGN(C); private: int *p; };
PS我知道GCC的-Weffc ++有几个问题。 检查“问题”的代码是非常简单的,无论如何…有时它有帮助。
根据斯科特·迈耶斯(Scott Meyers)的观点,这个缺点是“非天生的”,如果你确实需要find它的缺点的话。
我宁愿使用boost :: noncopyable比手动删除或私有化复制构造函数和赋值运算符。
但是,我几乎从不使用任何一种方法,因为:
如果我制作不可复制的对象,则必须有一个不可复制的原因。 这个原因,99%的时间,是因为我有成员,不能被有意义的复制。 有可能,这样的成员也会更适合作为私人实施细节。 所以我做了这样的大多数类:
struct Whatever { Whatever(); ~Whatever(); private: struct Detail; std::unique_ptr<Detail> detail; };
所以现在,我有一个私有的实现结构,因为我已经使用std :: unique_ptr,我的顶级类是不可复制的免费。 来自这个链接的错误是可以理解的,因为他们谈论你如何不能复制一个std :: unique_ptr。 对我来说,这是boost :: noncopyable的所有好处,并将私有实现合并为一个。
这个模式的好处在于,如果我确定我确实想让这个类的对象可拷贝,我可以添加和实现拷贝构造函数和/或赋值操作符,而不用改变类的层次结构。