boost :: noncopyable有什么优点

时间:2011-10-19 15:40:35

标签: c++ boost noncopyable

为了防止复制类,您可以非常轻松地声明私有复制构造函数/赋值运算符。但您也可以继承boost::noncopyable

在这种情况下使用boost有什么优点/缺点?

11 个答案:

答案 0 :(得分:45)

我认为没有文档优势:

#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派生出来并且是否会让我付出代价要容易得多。特别是如果我不是完整继承层次结构的作者。

答案 1 :(得分:42)

它使intent 显式且清晰,否则必须看到类的定义,并搜索与copy-semantic相关的声明,然后查找access-specifier,其中它是声明,以确定该类是否是不可复制的。通过编写需要启用了复制语义的代码来发现它的其他方法,并查看编译错误。

答案 2 :(得分:40)

总结其他人所说的话:

boost::noncopyable优于私人复制方法的优势

  1. 意图中更明确,更具描述性。使用私人复制功能是一种比noncopyable需要更长时间才能发现的习惯用法。
  2. 代码更少/更少打字/更少杂乱/更少错误空间(最容易意外提供实现)。
  3. 它在类型的元数据中嵌入了意义,类似于C#属性。您现在可以编写一个只接受不可复制对象的函数。
  4. 它可能会在构建过程的早期捕获错误。如果类本身或类的朋友正在进行错误的复制,则错误将在编译时而不是链接时显示。
  5. (与#4几乎相同)防止类本身或类的朋友调用私有拷贝方法。
  6. 私人复制方法优于boost::noncopyable 的优势:

    1. 没有提升依赖性

答案 3 :(得分:16)

  1. boost :: noncopyable的意图更清晰。
  2. Boost :: noncopyable可防止类方法意外使用私有拷贝构造函数。
  3. 使用boost :: noncopyable减少代码。

答案 4 :(得分:16)

我无法理解为什么没有其他人似乎提到它,但是:

使用noncopyable,您只需编写一次类名称。

没有,五倍重复: 一个用于'A类',两个用于禁用赋值,两个用于禁用复制构造函数。

答案 5 :(得分:9)

引用文档:

“处理这些问题的传统方法是声明私有拷贝构造函数和拷贝赋值,然后记录为什么这样做。但是从noncopyable派生更简单,更清晰,并且不需要额外的文档。 “

http://www.boost.org/libs/utility/utility.htm#Class_noncopyable

答案 6 :(得分:8)

一个具体的优点(除了更清楚地表达你的意图)是错误将在编译阶段而不是链接阶段更快地被捕获,如果成员或朋友函数试图复制对象。无法在任何地方访问基类构造函数/赋值,从而产生编译错误。

它还可以防止您意外地定义函数(即键入{}而不是;),这是一个很小的错误,可能会被忽视,但会让成员和朋友制作无效的副本对象。

答案 7 :(得分:3)

优点是您不必自己编写私有拷贝构造函数和私有拷贝操作符,并且在不编写其他文档的情况下明确表达您的意图。

答案 8 :(得分:3)

缺点(GCC特定)是,如果使用g++ -Weffc++编译程序并且您有包含指针的类,例如

class C : boost::noncopyable
{
public:
  C() : p(nullptr) {}

private:
  int *p;
};

GCC不明白发生了什么:

  

警告:'class C'有指针数据成员[-Weffc ++]
  警告:但不会覆盖'C(const S&amp;)'[ - Weffc ++]
  警告:或'operator =(const C&amp;)'[ - 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 ++有几个问题。无论如何,检查“问题”的代码非常简单......有时它会有所帮助。

答案 9 :(得分:2)

我宁愿使用boost :: noncopyable而不是手动删除或私有化复制构造函数和赋值运算符。

但是,我几乎从不使用 方法,因为:

如果我正在制作一个不可复制的对象,则必须有一个不可复制的原因。这个原因,99%的时间,是因为我有无法有意义地复制的成员。有可能,这些成员也更适合作为私人实施细节。所以我创造了大多数这样的类:

struct Whatever {
  Whatever();
  ~Whatever();
  private:
  struct Detail;
  std::unique_ptr<Detail> detail;
};

所以现在,我有一个私有实现结构,因为我使用了std :: unique_ptr,我的顶级类是免费的非可复制的。来自此的链接错误是可以理解的,因为它们讨论了如何不能复制std :: unique_ptr。对我来说,这就是boost :: noncopyable和私有实现的所有好处。

这种模式的好处是后来的,如果我确定我确实想让我的这个类的对象可以复制,我可以添加并实现一个复制构造函数和/或赋值运算符而不改变类层次结构。

答案 10 :(得分:1)

斯科特迈耶斯认为,如果你确实需要找到它的缺点,那么这个名字就是“非天生的”。