为了防止复制类,您可以非常容易地声明一个私有复制构造函数/赋值运算符。但是您也可以继承boost::noncopyable
。
在这种情况下使用升压有什么优点/缺点?
为了防止复制类,您可以非常容易地声明一个私有复制构造函数/赋值运算符。但是您也可以继承boost::noncopyable
。
在这种情况下使用升压有什么优点/缺点?
Foo & operator=(const Foo &) = delete;
吗?
Answers:
我看不出任何文档方面的好处:
#include <boost/noncopyable.hpp>
struct A
: private boost::noncopyable
{
};
vs:
struct A
{
A(const A&) = delete;
A& operator=(const A&) = delete;
};
当您添加仅移动类型时,我什至认为文档具有误导性。以下两个示例虽然可以移动,但不可复制:
#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;
};
在多重继承下,甚至会有空间损失:
#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::noncopyable
它早在C ++ 11之前就已经存在,并且对进行了编译支持= delete
。我确实同意您的观点,即对于C ++ 11接近兼容的编译器,现在已经过时了。
noncopyable
一个CRTP基类,这样层次结构中的所有基类都是唯一的。
private: __copy_constructor__;
是完全可移植的,并且不需要〜40 MB的Boost依赖项。
std::vector<std::unique_ptr<animal>>
在到达之前使用boost::ptr_vector<animal>
(boost.org/doc/libs/1_54_0/libs/ptr_container/doc/tutorial.html)。原理:如果我知道vector
,并且我知道unique_ptr
,那么我知道unique_ptr向量的语义。而且我知道std :: algorithms(例如sort)如何与之交互。我不必学习有关其成员算法(例如,成员排序)的新容器的全部知识。
它使意图明确和清晰的,否则,人们必须看到类的定义,并搜索相关的拷贝语义的声明,然后寻找其被访问说明符声明,以确定是否该类是否不可复制。通过编写要求启用了复制语义的代码来发现它的其他方法,并查看编译错误。
noncopyable
。所以这是有争议的。
总结别人说的话:
boost::noncopyable
优于私有复制方法的优点:
noncopyable
。私有复制方法相对于boost::noncopyable
:
引用文档:
“处理这些问题的传统方法是声明一个私有副本构造函数和副本赋值,然后记录为什么这样做。但是,从不可复制派生的过程更加简单明了,并且不需要其他文档。”
http://www.boost.org/libs/utility/utility.htm#Class_noncopyable
一个具体的优势(除了更清晰地表达您的意图之外)是,如果成员或朋友函数尝试复制对象,则将在编译阶段而不是链接阶段更快地捕获错误。基类构造函数/赋值在任何地方都无法访问,从而产生编译错误。
它还可以防止您意外地定义函数(即,键入{}
而不是;
),这是一个很小的错误,很可能不会引起注意,但是会允许成员和朋友创建该对象的无效副本。
...is that the error will be caught sooner, at the compile stage not the link stage
。到底如何 即使boost::noncopyable
您不使用它,也会执行相同的操作。
noncopyable
基类,则在类中声明一个私有构造函数。这是从类的成员和朋友的访问,所以没有编译错误-只是一个链接错误,由于缺少定义。(除非您不小心提供了定义-使用基类也将防止该错误)。
一个小缺点(特定于GCC)是,如果使用编译程序,g++ -Weffc++
并且具有包含指针的类,例如
class C : boost::noncopyable
{
public:
C() : p(nullptr) {}
private:
int *p;
};
GCC不了解发生了什么:
警告:“类C”具有指针数据成员[-Weffc ++]
警告:但不会覆盖“ C(const 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 ++有几个问题。无论如何,检查“问题”的代码非常简单……有时会有所帮助。
我宁愿使用boost :: noncopyable而不是手动删除或私有化复制构造函数和赋值运算符。
但是,我几乎从不使用任何一种方法,因为:
如果我要制作不可复制的对象,则必须有一个不可复制的原因。99%的原因是因为我的成员无法被有意义地复制。这样的成员很可能也更适合作为私有实施细节。因此,我制作了大多数这样的类:
struct Whatever {
Whatever();
~Whatever();
private:
struct Detail;
std::unique_ptr<Detail> detail;
};
因此,现在,我有了一个私有实现结构,并且由于使用了std :: unique_ptr,所以我的顶级类是免费不可复制的。由此产生的链接错误是可以理解的,因为它们讨论了如何无法复制std :: unique_ptr。对我而言,这就是boost :: noncopyable的全部好处,并且私有实现集成为一个。
这种模式的好处是以后,如果我确定确实要使该类的对象可复制,则可以在不更改类层次结构的情况下添加并实现一个复制构造函数和/或赋值运算符。
struct Foo{Foo(const Foo&)=delete;};