boost::noncopyable的优点是什么?
What are the advantages of boost::noncopyable
为了防止复制类,可以很容易地声明私有复制构造函数/赋值操作符。但是你也可以继承boost::noncopyable
在这种情况下使用boost的优点/缺点是什么?
我没有看到文档的好处:
#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
相对于私有复制方法的优势:
- 在意图上更加明确和描述性。使用私有复制函数是一种比
noncopyable
更容易发现的习惯用法。 - 更少的代码/更少的输入/更少的混乱/更少的错误空间(最简单的是意外提供实现)。
- 它将含义嵌入到类型的元数据中,类似于c#属性。你现在可以编写一个只接受不可复制对象的函数。
- 它可能在构建过程的早期捕获错误。如果类本身或类的友类正在进行错误的复制,则该错误将在编译时而不是链接时显示。
- (几乎与#4相同)防止类本身或类的友类调用私有复制方法。
私有复制方法相对于boost::noncopyable
的优势:
- 没有boost依赖
它使意图显式和清晰,否则必须查看类的定义,并搜索与复制语义相关的声明,然后查找在其中声明的访问说明符,以确定类是否不可复制。另一种发现方法是编写需要启用复制语义的代码并查看编译错误。
- boost::noncopyable的目的更清晰。
- Boost::noncopyable防止类方法意外使用私有复制构造函数。
- 使用boost::noncopyable来减少代码。
我不明白为什么没有人提到这件事,但是:
使用noncopyable
,您只需写一次类名。
Without, 五倍复制:一个A用于"类A",两个用于禁用赋值,两个用于禁用复制构造函数。
引用文档:
"处理这些问题的传统方法是声明一个私有复制构造函数和复制赋值,然后说明这样做的原因。但是从noncopyable派生更简单、更清晰,并且不需要额外的文档。"
http://www.boost.org/libs/utility/utility.htm#Class_noncopyable
一个具体的优点(除了稍微更清楚地表达您的意图之外)是,如果成员或友元函数试图复制对象,则错误将在编译阶段而不是链接阶段更快地被捕获。基类构造函数/赋值在任何地方都不可访问,从而导致编译错误。
它还可以防止您不小心定义函数(即输入{}
而不是;
),这是一个很可能被忽视的小错误,但这会允许成员和友元创建对象的无效副本。
一个小的缺点(特定于GCC)是,如果你用g++ -Weffc++
编译你的程序,并且你有包含指针的类,例如
class C : boost::noncopyable
{
public:
C() : p(nullptr) {}
private:
int *p;
};
GCC不明白发生了什么:
警告:'class C'有指针数据成员[- weffc++]
警告:但不覆盖'C(const S&)' [- weffc++]
警告:or '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和私有实现合而为一的所有好处。
这种模式的好处是,如果我后来决定我确实想让这个类的对象可复制,我可以添加和实现复制构造函数和/或赋值操作符,而不改变类的层次结构。缺点,根据Scott Meyers的说法,这个名字是"非自然的",如果你确实需要找到它的缺点
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++中名称篡改的目的是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 派生类销毁的最佳实践是什么
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 通过JNI传递数据数组的最快方法是什么
- "using namespace std;"在C++的作用是什么?
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 文件系统:复制功能的速度秘诀是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- boost::noncopyable的优点是什么?